起订量和访问调用的参数

发布于 2024-08-17 19:32:42 字数 516 浏览 4 评论 0原文

我刚刚开始在我已经建立的项目上实施单元测试(使用 xUnit 和 Moq)。该项目通过统一容器广泛使用依赖注入。

我有两个服务 A 和 B。服务 A 是本例中正在测试的服务。服务 A 调用 B 并为其提供内部函数的委托。当收到必须处理的消息时,此“回调”用于通知 A。

因此 A 调用(其中 b 是服务 B 的实例):

b.RegisterHandler(Guid id, Action<byte[]> messageHandler);

为了测试服务 A,我需要能够调用 messageHandler,因为这是它当前接受消息的唯一方式。

这可以使用起订量来完成吗? IE。我可以模拟服务 B,以便在调用 RegisterHandler 时,将 messageHandler 的值传递给我的测试吗?

或者我需要重新设计这个吗?在这种情况下我应该使用任何设计模式吗?有谁知道这种设计有什么好的资源吗?

I've just started to implement unit tests (using xUnit and Moq) on an already established project of mine. The project extensively uses dependency injection via the unity container.

I have two services A and B. Service A is the one being tested in this case. Service A calls B and gives it a delegate to an internal function. This 'callback' is used to notify A when a message has been received that it must handle.

Hence A calls (where b is an instance of service B):

b.RegisterHandler(Guid id, Action<byte[]> messageHandler);

In order to test service A, I need to be able to call messageHandler, as this is the only way it currently accepts messages.

Can this be done using Moq? ie. Can I mock service B, such that when RegisterHandler is called, the value of messageHandler is passed out to my test?

Or do I need to redesign this? Are there any design patterns I should be using in this case? Does anyone know of any good resources on this kind of design?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

尤怨 2024-08-24 19:32:42

您可以通过使用 Mock 上的 Callback(名称相似性是偶然的)方法来获取回调(或任何其他输入参数)的实例:

[TestMethod]
public void Test19()
{
    Action<byte[]> callback = null;

    var bSpy = new Mock<IServiceB>();
    bSpy.Setup(b => b.RegisterHandler(It.IsAny<Guid>(), It.IsAny<Action<byte[]>>()))
        .Callback((Guid g, Action<byte[]> a) => callback = a);

    var sut = new ServiceA(bSpy.Object);
    sut.RegisterCallback();

    Assert.AreEqual(sut.Do, callback);
}

当 ServiceA 定义如下时,此方法有效:

public class ServiceA
{
    private readonly IServiceB b;

    public ServiceA(IServiceB b)
    {
        if (b == null)
        {
            throw new ArgumentNullException("b");
        }

        this.b = b;
    }

    public void RegisterCallback()
    {
        this.b.RegisterHandler(Guid.NewGuid(), this.Do);
    }

    public void Do(byte[] bytes)
    {
    }
}

You can get an instance of the callback (or any other input parameter) by using the Callback (the name similarity is incidental) method on the Mock:

[TestMethod]
public void Test19()
{
    Action<byte[]> callback = null;

    var bSpy = new Mock<IServiceB>();
    bSpy.Setup(b => b.RegisterHandler(It.IsAny<Guid>(), It.IsAny<Action<byte[]>>()))
        .Callback((Guid g, Action<byte[]> a) => callback = a);

    var sut = new ServiceA(bSpy.Object);
    sut.RegisterCallback();

    Assert.AreEqual(sut.Do, callback);
}

This works when ServiceA is defined as this:

public class ServiceA
{
    private readonly IServiceB b;

    public ServiceA(IServiceB b)
    {
        if (b == null)
        {
            throw new ArgumentNullException("b");
        }

        this.b = b;
    }

    public void RegisterCallback()
    {
        this.b.RegisterHandler(Guid.NewGuid(), this.Do);
    }

    public void Do(byte[] bytes)
    {
    }
}
感情洁癖 2024-08-24 19:32:42

是的,您可以设置 Moq 对象来响应预期和意外的操作。
这是一个 Visual Studio 单元测试示例...

[TestMethod]
public void MyTest()
    {
      var moqObject = new Mock<ServiceB>();

      // Setup the mock object to throw an exception if a certain value is passed to it...
      moqObject.Setup(b => b.RegisterHandle(unexpectedValue).Throws(new ArgumentException());

      // Or, setup the mock object to expect a certain method call...
      moqObject.Setup(b => b.RegisterHandle(expectedValue));

      var serviceA = new ServiceA(moqObject.Object);

      serviceA.DoSomethingToTest();

      // This will throw an exception if an expected operation didn't happen...
      moqObject.VerifyAll();
    }

Yes you can setup the Moq object to respond to expected and unexpected operations.
Here's a Visual Studio Unit Test example...

[TestMethod]
public void MyTest()
    {
      var moqObject = new Mock<ServiceB>();

      // Setup the mock object to throw an exception if a certain value is passed to it...
      moqObject.Setup(b => b.RegisterHandle(unexpectedValue).Throws(new ArgumentException());

      // Or, setup the mock object to expect a certain method call...
      moqObject.Setup(b => b.RegisterHandle(expectedValue));

      var serviceA = new ServiceA(moqObject.Object);

      serviceA.DoSomethingToTest();

      // This will throw an exception if an expected operation didn't happen...
      moqObject.VerifyAll();
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文