One Mock Per Test

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 (6) left to “One Mock Per Test”

  1. Aaron Jensen wrote:

    I agree with most of what you said, however I don’t know that alternating between stubs and mocks in your tests really adds any value. If you just use dynamic mocks for everything, which is the default if you’re using the AutoMockingContainer (another post on that coming soon), you’ll get pretty much the same 1 “assertion” per test you’re wanting by using mocks.

    The key is liberal usage of SetupResult.For() and LastCall.PropertyBehavior(). Just be sure to Expect.Call() anything you actually want to be called (and verify it). The benefit is that you can simplify the way your tests look… you just always construct the subject under test with the same dynamic mocks (or that happens automatically w/ AMC) rather than declaring stubs and substituting mocks when you need to.

    Dynamic”Mocks” are “stubs” until you tell them not to be… for the most intents and purposes.

    I mean… isn’t this nicer:
    private MockRepository _mocks;
    private AutoMockingContainer _container;
    private SearchPresenter _presenter;
    private SearchResultDTO _fakeResults;

    [SetUp]
    public void Setup()
    {
    this._mocks = new MockRepository();
    this._container = new AutoMockingContainer(_mocks);
    this._presenter = _container.Create();
    this._fakeResults = new SearchResultDTO();
    }

    [Test]
    public void Can_search_for_customers_by_number_of_orders()
    {
    using (_mocks.Record())
    {
    Expect
    .Call(_container.Get().GetCustomersByOrderCount(42))
    .Return(this._fakeResults);
    }

    using (_mocks.Playback())
    {
    _presenter.SearchByOrderCount(42);
    }
    }

    [Test]
    public void Search_results_are_displayed_to_the_user()
    {
    using (_mocks.Record())
    {
    mockView.SearchResults = _fakeResults;
    SetupResult
    .For(_container.Get().GetCustomersByOrderCount(42))
    .Return(_fakeResults);
    }

    using (_mocks.Playback())
    {
    presenter.SearchByOrderCount(42);
    }
    }

  2. Aaron Jensen wrote:

    Erg my generic type specifies didn’t show up… replace all the Gets with Get<ISearchService>

  3. Dave wrote:

    That is much nicer! (And a good point re: DynamicMocks.) I hope people will focus on the content after “so what’s the benefit of the single mock approach?”

    You would use your container to resolve the service dependency transitively? I guess why not if you use the AMC…

  4. Dave wrote:

    @Aaron - nevermind, the service is reg’d singleton.

  5. Aaron Jensen wrote:

    Yeah, everything that the AMC resolves is a singleton. It’s then cached so that you can retrieve it with Get<T>();. You can also call Get before you ever do a Create if you need to set up those mocks before the constructor.

  6. Ben Scheirman wrote:

    Good info. This has been my current pain point with mocks, so I will try breaking them apart and get back into rhythm.

    Thanks!

Post a Comment

*Required
*Required (Never published)