Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 801
nivlam Avatar asked Aug 20 '26 02:08

nivlam


2 Answers

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.

like image 80
Tim Barrass Avatar answered Aug 21 '26 17:08

Tim Barrass


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

like image 28
Mr.Eddart Avatar answered Aug 21 '26 17:08

Mr.Eddart



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!