C# 模拟以验证交互

C# 模拟以验证交互,c#,.net,unit-testing,mocking,rhino-mocks,C#,.net,Unit Testing,Mocking,Rhino Mocks,通常,当我需要模拟类进行测试时,我会使用Rhino Mocks之类的库。这里我有一个名为MyService的类,它需要一个iemailssender public class MyService { private readonly IEmailSender sender; public MyService(IEmailSender sender) { this.sender = sender; } public void Start(

通常,当我需要模拟类进行测试时,我会使用Rhino Mocks之类的库。这里我有一个名为
MyService
的类,它需要一个
iemailssender

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()
        );
}

对于我手动创建的mock,如何验证调用了
sendmail()
方法?我可以将我的断言放在模拟的
sendmail()
方法中,但这会使测试很难理解,因为当我查看测试时,我不会立即看到发生了什么。

我认为除了在“sendmail()”中设置一个标志之外,没有其他选择,并通过MockEmailSender的新方法(如“SendmailwasCalled()”或类似的东西)从测试中检查该标志(实际上是一种“验证”)。
您可以扩展它来计算调用、参数的数量…

我建议不要创建任何手动模拟(因为如果您向接口添加新方法,它会被破坏)

如果你真的必须这样做,当你在MockEmailSender中公开一些计数器/bool时,你可以在以后断言它


Assert.IsTrue(emailSender.IsCalled)

一个非常简单的解决方案是让您的手动模拟成为一个状态持有者,为每个方法的调用提供计数器。但它很脆弱

public class MockEmailSender : IEmailSender
{
    public int SendCount = 0;

    public void SendMail(...)
    {
        SendCount++;
    }

    // ... other IEmailSender methods ...
}
然后,在进行方法调用之后,只需查询SendCount,并确保它为==1

记住,Rhino Mocks是为您动态创建的——如果您手动创建,您必须在编译前手动对接口更改做出反应

public class MockEmailSender : IEmailSender
{
    public int SendCount = 0;

    public void SendMail(...)
    {
        SendCount++;
    }

    // ... other IEmailSender methods ...
}