For some reason I came across a rule of thumb that says something like this:

You should have only one mock per test; all other interactions must be stubbed.

That sounds like good advice, but it is not. This rule of thumb does not really help you write good tests, and it can easily lead you to test the wrong thing.

I am not terribly strict with nomenclature, but for this article I will try to stick to the generally accepted differences between mocks and stubs:

  • Stubs: If called during a test, they provide canned responses. If not called, they do nothing. They never break a test.
  • Mocks: They expect the test to interact with them in a specific way. They fail the test if the actual interaction is not what was expected.

It seems like the rule above was first published by Roy Osherove in his book The Art of Unit Testing. This article is not a review of Osherove’s book. I had not read it at the time; I had just bought the ebook and read enough to understand how he presented the rule.

I think it is fair to summarise it like this:

In a test where you test only one thing […] there should be no more than one mock object. All other fake objects will act as stubs. Having more than one mock per test usually means you’re testing more than one thing, and this can lead to complicated or brittle tests. […] Once you’ve identified [your single mock object] you can leave the others as stubs and not worry about assertions against them.

Wrong Focus

For me, tests are much like paragraphs. If you read about how a good paragraph is structured, you will often find advice like this:

A paragraph is a piece of writing that consists of several sentences. A paragraph should always have complete, correct, and concise sentences. As well it should be easy to read and well organised. The paragraph itself should focus on one subject, theme, or central idea.

[…]

When examining a paragraph you can always ask yourself, what is the main idea in this paragraph? If you see two ideas […] you might have to create two paragraphs.

Writing.com

So Roy is right when he says that “testing more than one thing […] can lead to complicated or brittle tests”. For me, the problem is that this focuses on the wrong way to solve it.

The one subject, theme, or central idea a test should focus on should not be object interactions. That can be the case for Integration Tests — where the focus is on how different parts of a system get along — but not for Unit Tests.

When writing Unit Tests we should not be concerned with specifying how a class does its job or which other classes it talks to. That leads to heavy coupling between test and implementation, and this is just as bad as testing many things at once, if not worse.

A Unit Test should focus on specifying what a class does. We should focus on describing what behaviour we expect from that class. How it achieves that is not the unit test’s problem; that is design.

As a completely biased example, let’s say we want to write some code that lets us post status updates to multiple social networks. Following the one-mock-per-test rule, we will probably end up with something like this:

public void ShouldUpdateFacebook ()
{
  var message = "Having a beer.";
  var twitter = MockRepository.GenerateStub<Twitter>();
  var facebook = MockRepository.GenerateMock<Facebook>();

  facebook.Expect(f => f.Update(message));

  var updater = new StatusUpdater(facebook,twitter);
  updater.Update(message);

  facebook.VerifyAllExpectations();
}

[Test()]
[ExpectedException(typeof(StatusUpdateException))]
public void ShouldThrowExceptionIfFacebookUpdateFails ()
{
  var message = "Having a beer.";
  var twitter = MockRepository.GenerateStub<Twitter>();
  var facebook = MockRepository.GenerateMock<Facebook>();

  facebook.Expect(f => f.Update(message)).Throw(new FacebookException());

  new StatusUpdater(facebook,twitter).Update(message);
}

[Test()]
public void ShouldUpdateTwitter ()
{
  var message = "Having a beer.";
  var twitter = MockRepository.GenerateMock<Twitter>();
  var facebook = MockRepository.GenerateStub<Facebook>();

  twitter.Expect(t => t.Update(message));

  var updater = new StatusUpdater(facebook,twitter);
  updater.Update(message);

  twitter.VerifyAllExpectations();
}

[Test()]
[ExpectedException(typeof(StatusUpdateException))]
public void ShouldThrowExceptionIfTwitterUpdateFails ()
{
  var message = "Having a beer.";
  var twitter = MockRepository.GenerateMock<Twitter>();
  var facebook = MockRepository.GenerateStub<Facebook>();

  twitter.Expect(twit => twit.Update(message)).Throw(new TwitterException());

  new StatusUpdater(facebook,twitter).Update(message);
}

This test provides good code coverage. It is hard to introduce a bug that will not break it somehow. That is all good, but let me remind you again that what we should be automating here is not just tests; we should be automating specifications.

Even if the test above covers all execution scenarios, it is a terrible specification for what the class should do. It does not even talk about the most important expected behaviour for this class: the fact that it must update all social networks at once.

And why does it not specify this? Because it is not easy — perhaps not even possible — to do that without using more than one mock. And this is no exception; it is a very common scenario in most systems.

Verifying Side Effects Isn’t the Goal

If we want to finally add a proper test that verifies whether the class does what it should do — send the same status update to all systems — we have to break the one-mock-per-test rule.

The reason we have to break it is very simple: mocks verify side effects, and having more than one side effect during a test does not mean testing more than one thing. Writing good tests is about asking yourself “why should I bother?” all the time; and instead of bothering about interactions, we should bother about writing good specifications.

I do not use mocks a lot, and even for stubs I spend a lot of time thinking about which collaborations should be tested using a double, mock, or stub and which are just part of the object. The only case in which I use a mock is when I have to test some side effect.

Having to use too many mocks in a test is definitely a bad smell; something is odd in your code. That does not mean, though, that reducing the number of mocks in a test to one is a good thing.

Using mocks and interactions as drivers for test cases pulls you away from good specifications. Always keep in mind that we should care about what, not how.