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 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)
精彩评论