One Mock Per Test

by Dave on August 4, 2007

in Old Blog

Update: I’ve slightly revised my viewpoint on this. Hooray for changing one’s mind!

At my last talk I casually threw out the idea that you should, generally speaking and as a rule of thumb, keep each test down to a single mock. I my mind this is similar to the one-assert-per-test guideline. Consider this code snippet (using Rhino Mocks) and let’s pretend it came about through a TDD session which, as we may or may not see later, may or may not matter:

[TestFixture]
   public class SearchPresenterTests
   {
      private MockRepository _mocks;

      [SetUp]
      public void Setup()
      {
         _mocks = new MockRepository();
      }

      [Test]
      public void Can_search_for_customers_by_number_of_orders()
      {
         ISearchView mockView = _mocks.CreateMock<ISearchView>();
         ISearchService mockService = _mocks.CreateMock<ISearchService>();

         SearchResultDTO fakeResults = new SearchResultDTO();

         using (_mocks.Record())
         {
            Expect
                  .Call(mockService.GetCustomersByOrderCount(42))
                  .Return(fakeResults);

            mockView.SearchResults = fakeResults;
         }

         using (_mocks.Playback())
         {
            SearchPresenter presenter =
                  new SearchPresenter(mockView, mockService);

            presenter.SearchByOrderCount(42);
         }
      }
   }

A user fills out a textbox with a parameter value, clicks a button who’s click event handler calls back to a “Search” method on our presenter giving it the parameter value. It’s a pretty standard scenario for MVP.

Well what’s wrong with this? At first blush nothing. It’s a fairly minimal. The problem is that word fairly. It’s a slippery slope friends and this test is getting a bit beefy for my tastes; I’m testing two behaviors. I’ve got two specifications here: 1) “A user can search for customers by order count” and 2) “Search results are displayed to the end user.” I took a pretty big step there.

Of course, I’m making this stuff up, but let’s go with it and make the tests and break the tests in twain (for the impatient reader, skip to the bottom where I get to the why):

      private MockRepository _mocks;
      private ISearchService _stubService;
      private ISearchView _stubView;
      private SearchResultDTO _fakeResults;

      [SetUp]
      public void Setup()
      {
         this._mocks = new MockRepository();
         this._fakeResults = new SearchResultDTO();
         this._stubView = _mocks.Stub<ISearchView>();
         this._stubService = this._mocks.Stub<ISearchService>();
      }

      [Test]
      public void Can_search_for_customers_by_number_of_orders()
      {
         ISearchService mockService = _mocks.CreateMock<ISearchService>();

         using (_mocks.Record())
         {
            Expect
                  .Call(mockService.GetCustomersByOrderCount(42))
                  .Return(this._fakeResults);
         }

         using (_mocks.Playback())
         {
            SearchPresenter presenter =
                  new SearchPresenter(_stubView, mockService);

            presenter.SearchByOrderCount(42);
         }
      }

      [Test]
      public void Search_results_are_displayed_to_the_user()
      {
         ISearchView mockView = _mocks.CreateMock<ISearchView>();

         mockView.SearchResults = _fakeResults;

         SetupResult
               .For(_stubService.GetCustomersByOrderCount(42))
               .Return(_fakeResults);

         _mocks.ReplayAll();

         SearchPresenter presenter = new SearchPresenter(mockView, _stubService);

         presenter.SearchByOrderCount(42);

         _mocks.Verify(mockView);
      }
   }

What I did here was to make running the search independent from displaying the search results. You’ll notice that each test uses a single mock. In the case of the second test I use a stub to stand in for the service; I don’t really care about the search service in this test, it’s just there to get the job done and return some dummy results.

So what’s the benefit of the single mock approach? Well, first it keeps your test-code cycle short. That is, by keeping your tests small you design less code before returning to test. This is absolutely key when adopting a continuous design philosophy. You don’t want to let things go to far or your discipline is likely to break down.

You’ve maybe heard the whole single assertion per test tip, right? Well a mock is really a type of assertion. You’re asserting get to callin’ this here code if you expect to pass. Stubs aren’t assertions. They’re more like saying: dear code under test, I need you to run so here’s a dummy that will get you to the scenario I need.

The main thing for me with this approach is that I get a higher quantity of smaller but more focused tests. It’s a small price to pay because your test code becomes a little more agile against the “real” code. When a small, well-named test breaks it’s easier to identify at a glance what broke it. This can be really handy in speeding you up when you’re refactoring or making behavioral changes to code in some other area of your test suite. Consider me wanting to introduce a caching layer or a dirty check on the view between getting search results and displaying them. These tests, beyond requiring a new constructor dependency, wouldn’t necessarily break or, at most, would require another stub. The nature of the behavior I’m testing (specified by the test name) simply does not change.

Also, yes it merits repeating, tiny tests equal more frequent test-code iterations equal better discipline equal better chance of sticking with TDD! This, for folks new to the technique, will greatly increase your chance and feelings of success.

Comments on this entry are closed.

blog comments powered by Disqus

Previous post:

Next post: