我刚开始在已经建立的项目中实施单元测试(使用xUnit和Moq)。该项目通过统一容器广泛使用依赖注入。
我有两个服务A和B.服务A是在这种情况下正在测试的服务。服务A调用B并为其提供内部函数的委托。这个'回调'用于在收到必须处理的消息时通知A.
因此A调用(其中b是服务B的实例):
b.RegisterHandler(Guid id, Action<byte[]> messageHandler);
为了测试服务A,我需要能够调用messageHandler
,因为这是它当前接受消息的唯一方式。
可以使用Moq完成吗?即。我可以模拟服务B,这样当调用RegisterHandler
时,messageHandler
的值会传递给我的测试吗?
或者我需要重新设计吗?在这种情况下,我应该使用任何设计模式吗?有谁知道这种设计有什么好的资源吗?
答案 0 :(得分: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)
{
}
}
答案 1 :(得分: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();
}