Fork me on GitHub

Monday, August 17, 2009

Mocks and Verifying Expectations

Mocks are uber cool. They are really convenient to replace dependent components as well useful in TDDing out the behavior of an object and its collaborators. But what I have seen people doing is using mock and ceremoniously verify the expectations (in case of RhinoMocks it is using VerifyAllExpectations) and I question this. Here are my views on this practice.

Example -
public void GreetInFrench()
{
var translator = MockRepository.GenerateMock();
translator.Expect(tr => tr.Translate("English", "French", "Hello")).Return("Bonjour").Repeat.Once();
var greeting = new Greeting(translator);
greeting.SayHello("French", "Sai");
translator.VerifyAllExpectations();
}


Above test has been written using RhinoMocks framework. But the important point to note is, is it really necessary to verify if the expectation we set on translation mock is satisfied or not at the end of the test?

For me mock expectation is a form of assertion and in a test I don't like to assert on something which is not related to the behavior of the object I am trying to evolve. So when I pass a collaborator to an object through constructor or some method do I really care how the collaborator gets used or do I care the behavior of the object is as expected? Well obviously I care about the behavior and not much about the collaborator. So the assertion happens on what the object returns on exercising that behavior and not whether collaborators have been used or not.

But when would I explicitly assert using a mock? When I really care about how the collaborator gets used or there is no way for me to observe the effects of the object behavior I am testing. Situation like these bring out the need for mock.
For example

1) If there is a condition which says retry thrice to contact mail server in case of failure I set an explicit expectation to verify that the method on mock is called thrice on the failure test. Or I have a spec which says every call to translator service costs 2$. Then again I explicitly verify that the service is called once through a mock translator service.

2) Or when I am at the boundary of my system working on something which sends messages to the outside world (like sending mails or printing something on screen such methods typically return void) then I have no way to observe the effects. Again in such case I use a explicit verification to see if the method has been called on mock


So for me a better way to write the initial test is

public void GreetInFrench()
{
var translator = MockRepository.GenerateStub();
translator.Stub(tr => tr.Translate("English", "French", "Hello")).Return("Bonjour");
var greeting = new Greeting(translator);
Assert.That(greeting.SayHello("French", "Paulo"), Is.EqualTo("Bonjour Paulo"));
}

Here we use a stub for translator as I have nothing to verify against it and it is up to the greeting object to use it. I am happy as long as my expectations with greetings object is met.

Every test we write is a form of specification and mocks at times helps us to makes some of the conditions in these specifications explicit. Making unnecessary expectations will confuse the reader of the test as it mangles the meaning of what we behavior are trying to evolve.

Well... These are my views on using mocks. If you feel the stuff is really confusing let me know I will try to explain in a different way. Or if you have an alternate view lets discuss :)

3 comments:

Paulo Caroli said...

I agree.

I feel guilty for the times I added verify to unit tests just because I could.

In fact you post is the core of the distinction of stubs and mocks; several times, stub is enough. IMO we get excited with the mock object framework features and end up using more than needed.

Below is a test sample (Java, JUnit and Mockito) for the Publisher/Subscriber. In this case, it is clear that the mock is necessary for verifying the behavior in the SUT (Publisher).

@Test
public void subscriberReceivesMessage() {
// set up
Publisher publisher = new Unicaster();
Subscriber subscriber = mock(Subscriber.class);
publisher.add(subscriber);

// execute
publisher.publish(MSG1);

// verify
verify(subscriber).receive(MSG1);
}



Mark Needham said...

I guess in the situations where you don't care about the expectation then you might as well just use a stub or fake instead.

Most of the mocking frameworks let you stub as well although under the covers a stub is just a mock that isn't verified so I guess either approach works out fine.

Good post though and I'm guilty of tightly coupling tests to code too!

Sai Venkatakrishnan said...

Yup... Think I missed mentioning about stubs. My bad (I blame sleeplessness for this :). The example has been updated to use a stub.