模拟以验证交互
本文关键字:交互 验证 模拟 | 更新日期: 2023-09-27 18:00:50
通常,当我需要模拟一个类进行测试时,我会使用Rhino Mocks之类的库。这里有一个名为MyService
的类,它需要一个IEmailSender
。
public class MyService
{
private readonly IEmailSender sender;
public MyService(IEmailSender sender)
{
this.sender = sender;
}
public void Start()
{
this.sender.SendEmail();
}
}
如果我需要测试这两个对象之间的交互,我的测试会是这样的:
[TestMethod]
public void Start_Test_Using_Rhino_Mocks()
{
IEmailSender emailSender = MockRepository.GenerateMock<IEmailSender>();
MyService service = new MyService(emailSender);
service.Start();
emailSender.AssertWasCalled
(
x => x.SendEmail(),
c => c.Repeat.Once()
);
}
在上面的测试中,我使用Rhino Mocks生成mock,并断言SendEmail()
方法被调用过一次。
但是,如果我不能使用Rhino Mocks,而不得不创建手动Mocks呢?
public class MockEmailSender : IEmailSender
{
public void SendEmail()
{
}
}
[TestMethod]
public void Start_Test_Using_Manual_Mocks()
{
MockEmailSender emailSender = new MockEmailSender();
MyService service = new MyService(emailSender);
service.Start();
// How do I test the interaction?
}
使用我手动创建的mock,我将如何验证是否调用了SendEmail()
方法?我可以把我的断言放在mock的SendEmail()
方法中,但这会让测试很难理解,因为当我查看测试时,我不会立即看到发生了什么。
一个非常简单的解决方案是让您的手动mock只是一个状态持有者,并为每个方法的调用提供计数器。但它很脆弱。。。
public class MockEmailSender : IEmailSender
{
public int SendCount = 0;
public void SendMail(...)
{
SendCount++;
}
// ... other IEmailSender methods ...
}
然后,只需在进行方法调用后查询SendCount,并确保其为==1。
记住,Rhino Mocks是为您动态创建的——如果您手动创建,则必须在编译前手动对接口更改做出反应。
我认为除了在"SendEmail(("中设置标志,并通过MockEmailSender的新方法(如"sendMailWasInvoked(("或类似的方法(从测试中检查该标志(实际上是一种"验证"(,您别无选择。您可以将其扩展为计算调用次数、参数。。。
我建议不要创建任何手动Mock(因为如果向接口添加新方法,它就会被破坏(。
如果你真的必须这样做,当你在MockEmailSender中暴露一些counter/bool时,你可以稍后断言它。
Assert.IsTrue(emailSender.IsCalled)