开发者

Mocks to verify interaction

开发者 https://www.devze.com 2023-03-16 04:51 出处:网络
Typically when I need to mock out a class for testing, I\'ll use a library such as Rhino Mocks.Here I have a class called MyService that expects a IEmailSender.

Typically when I need to mock out a class for testing, I'll use a library such as Rhino Mocks. Here I have a class called MyService that expects a IEmailSender.

public class MyService
{
    private readonly IEmailSender sender;

    public MyService(IEmailSender sender)
    {
        this.sender = sender;
    }

    public void Start()
    {
        this.sender.SendEmail();
    }
}

If I needed to test the interaction between these two objects, my test would look something like this:

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

In the test above, I'm using Rhino Mocks to generate the mock and assert that the SendEmail() method was called once.

But what if I could not use Rhino Mocks and had to create manual 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 interac开发者_运维百科tion?
}

With the mock that I created manually, how would I verify that the SendEmail() method was called? I could put my assertions in the SendEmail() method of the mock, but that would make the test hard to understand since I don't immediately see what's going on when I look at the test.


A very simple solution would have your manual mock just be a stateholder, with counters for the calls to each method. But it's fragile ...

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

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

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

Then just query SendCount after making your method call, and making sure that it's == 1.

Remember, Rhino Mocks is creating this dynamically for you -- if you do it manually you have to react to interface changes before compile time, by hand.


I think that you have no other option than setting a flag in "SendEmail()", and checking that flag from the test throgh a new method of MockEmailSender like "sendMailWasInvoked()" or something like this (which is in fact a kind of "verify"). You can extend this to count the number of invokations, parameters...


well i would advise against creating any manual Mocks (because if you add new method to interface, it gets broken).

if you really have to do it, when expose some counter/bool in your MockEmailSender and you can Assert it later on.

Assert.IsTrue(emailSender.IsCalled)

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号