Search code examples
c#.netunit-testingmockingrhino-mocks

Mocks to verify interaction


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 interaction?
}

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.


Solution

  • 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.