5

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

我有两个服务 A 和 B。在这种情况下,服务 A 是要测试的。服务 A 调用 B 并将其委托给内部函数。此“回调”用于在收到必须处理的消息时通知 A。

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

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

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

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

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

4

2 回答 2

9

您可以使用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)
    {
    }
}
于 2010-01-14T11:52:46.047 回答
0

是的,您可以设置 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();
    }
于 2010-01-14T11:42:30.420 回答