Inside the Sausage Factory: PART 22 (Mocking the View)

In our last post we built the beginnings of the View and the Presenter parts of our home-grown Model-View-Presenter approach to the User Interface for our application.  Although it would seem our next step would be to begin building the actual user interface that will interact with our Presenter, that’s not quite true.

Building even the prettiest of facades on top of a rotted foundation leads to the collapse of buildings as surely as doing the same will lead to the collapse of our software project.  Despite some of the points I raised in this post about the differences between software projects and other engineering/architecture projects, I firmly believe that this is an area of commonality between the two.

Just as we first wrote a reasonable suite of unit tests for our Data Access Layer before beginning to build the next layer atop it, we also need to write a set of tests for the beginnings of our Presenter class and its View interface.  As before, we are dutifully following the philosophy that we need to ensure our foundation layers are well-constructed before we proceed to build anything on top of them.

Testing the Presenter

Testing our presenter is fairly straightforward since at this point it exposes only two public methods:

  • InitializeView() <– setups up the view with its initial values to display to the user
  • PerformSearch() <– called by the view to actually do a search for people from the database

Just as the presenter needs a view and a dataprovider in order to do its real work in our application, it needs the same in order to function under test.  So that we don’t need a real view and we don’t need a real dataprovider to support our tests, we will use Mock Objects in place of these dependencies when we develop our tests.

If we look again at the two constructors for our presenter, we can begin to imagine how to accomplish testing it by feeding it mock objects in place of its ‘real’ dependencies.  Our presenter has two constructor signatures:

public PersonSearchCriteriaPresenter(IPersonSearchCriteriaView view): this(view, new DataProvider())

…and…

public PersonSearchCriteriaPresenter(IPersonSearchCriteriaView view, DataProvider dataProvider)

We can already see that the first of these two is going to be unusable for our testing since it only allows us to pass in an explicit IPersonSearchCriteriaView instance and then creates its own DataProvider.  Since it is creating its own dataprovider, this will of course be a real dataprovider and we want instead to force the use of a mock instance of our dataprovider.  This is the purpose of the second of the two constructors that enables us to pass in both a view of our choosing and a dataprovider of our choosing.  These will both be mocked using our Mock Object framework of choice: Rhino Mocks.

Testing the InitializeView( ) method

As is nearly always the case in unit test classes that use mocks, we need an instance of the mock-creating object provided by the framework.  To make access to this easy, we will both declare this as a field in our test class as well as ensure its always created for our tests by instantiating it in our TestFixtureSetup-attributed method as…

    [TestFixture]
    public class PersonSearchCriteriaPresenterTest
    {
        private MockRepository _mocks;

        [TestFixtureSetUp]
        public void FixtureSetup()
        {
            _mocks = new MockRepository();
        }

In the beginning of our test method, we need the mock object framework to create for us a mocked version of a View and another of a DataProvider object…

        [Test]
        public void InitializeViewTest()
        {
            IPersonSearchCriteriaView view = _mocks.CreateMock<IPersonSearchCriteriaView>();
            DataProvider provider = _mocks.CreateMock<DataProvider>();

There are a number of usage-syntax patterns supported by Rhino Mocks and I leave the user to review the documentation at their leisure to determine which is their preference.  Personally I’m a fan of the  syntax that makes use of the using keyword introduced in C# 2.0.

So the next thing we do in our test is set our expectations for our mock objects…

            using (_mocks.Record())
            {
                //expections on the call to the view
                Expect.Call(view.PersonTypes).PropertyBehavior();
                Expect.Call(view.Regions).PropertyBehavior();
                Expect.Call(view.Offices).PropertyBehavior();
                Expect.Call(view.SkillCategories).PropertyBehavior();
                Expect.Call(view.Skills).PropertyBehavior();
                Expect.Call(view.SkillLevels).PropertyBehavior();
                Expect.Call(view.YearsSinceUsed).PropertyBehavior();
                Expect.Call(view.YearsUsed).PropertyBehavior();

                //expections on calls to the data provider
                Expect.Call(provider.GetAllPersonTypes()).Return(new List<PersonType>());
                Expect.Call(provider.GetAllRegions()).Return(new List<Region>());
                Expect.Call(provider.GetAllOffices()).Return(new List<Office>());
                Expect.Call(provider.GetAllSkillTypes()).Return(new List<SkillType>());
                Expect.Call(provider.GetAllSkills()).Return(new List<Skill>());
                Expect.Call(provider.GetAllSkillLevels()).Return(new List<SkillLevel>());

            }

Since the presenter under test is going to set the view’s properties that hold all the values for what will eventually be the drop-down lists, we need to set all these expectations up using the Rhino Mocks .PropertyBehavior() call.  This is another reason why I prefer Rhino Mocks over several other mocking frameworks — this method avoids the need to explicitly set both get_xxx and set_xxx expectations on the property and lets me do so implicitly with this single call on each of the properties.  I love tools that let me be lazy when I want to but also let me get my hands dirty if the need arises; Rhino Mocks easily fills that bill, providing an excellent balance between convenience methods and powerful methods.

For our dataprovider, I need to set the expectation that a call will be made to each of the methods listed and that each one should return a new List of the appropriate type as noted in the .Return(xxx) statements.  our expectations set, we can invoke the ‘Playback’ mode of the Rhino Mocks framework and interact with our mock objects as needed to perform some tests:

            using (_mocks.Playback())
            {
                PersonSearchCriteriaPresenter presenter = new PersonSearchCriteriaPresenter(view, provider);
                presenter.InitializeView();

                Assert.AreEqual(1, view.PersonTypes.Count);
                Assert.AreEqual(1, view.Regions.Count);
                Assert.AreEqual(1, view.Offices.Count);
                Assert.AreEqual(1, view.SkillCategories.Count);
                Assert.AreEqual(1, view.Skills.Count);
                Assert.AreEqual(1, view.SkillLevels.Count);

            }

In this test, we construct a new instance of the Presenter class that we are planning to test (PersonSearchCriteriaPresenter) and pass into it the Mock Objects we created earlier, view and provider.  The Presenter object created, we can simply call its .InitializeView() method to ask it to do its work.  Since the Presenter is responsible to populate a dummy item into each of the list of objects that are to become our selection lists, we can just call a series of MbUnit Asserts that each list has a single item in it.  This will validate for us that the method is performing as planned.

Recall that since our dataprovider has been mocked and no actual records are being retrieved from the database during this test, we get empty lists returned from the mocked dataprovider when it ‘fakes’ calling into the database.  A more comprehensive set of tests might actually use the Rhino Mocks Return() calls to mock the return of lists that hold some actual items in them and then our Asserts could be for more specific details about the contents of the lists or even that the number of items in the list was +1 vs. the number of items mocked to be returned from the database; these more comprehensive tests are a good idea (and we may in fact return to write them at some point) but this current set of Asserts is fine to get us started right now.

The InitializeView() method tested, we next need to test the PerformSearch() method.

Testing the PerformSearch() Method

Testing our next method begins in the same way as before, by asking Rhino Mocks to create mock instances of our view and our dataprovider so that we can (eventually) pass them to the Presenter in our test…

        [Test]
        public void PerformSearchTest()
        {

            IPersonSearchCriteriaView view = _mocks.CreateMock<IPersonSearchCriteriaView>();
            DataProvider provider = _mocks.CreateMock<DataProvider>();

Note that we are duplicating the same code that requests Mock Objects in the beginning of this test that we are also asking for in the beginning of the test for the InitializeView() method.

Unit Test purists will ask: why can’t this just go into the [TestFixtureSetup] method so its called once at the beginning of the test suite?  The answer is that we want (need?) to be 100% certain that our mocked instance of these classes is ‘fresh’ and specific to just this one test.  In my experience creating mocked instances of these things once and then reusing these instances over and over for each test is a recipe for some odd side-effects that can be difficult to troubleshoot.  Asking for newly-mocked instances of these at the beginning of the tests where they are needed is done defensively for extra safety.

Note that if it turns out that all our tests in this [TestFixture] actually require these same two mocked objects then it would be at least worth considering turning them into fields of the class and placing them into a single [Setup]-attributed method that gets called before each individual test.  However, if not all our unit tests depend on these same mocked objects then creating them before each test could introduce some unnecessary overhead into tests that don’t need them.

This points out a constant point of tension that exists when writing unit tests — the need to strike a balance between over-engineered and over-complex unit test code vs. the need to be concise and adhere to DRY principles.  As a general rule of thumb, when considering refactoring unit test code, I usually recommend erring on the side of sacrificing maybe a little bit of DRY in order to achieve speed and performance since there is a very real need to ensure that unit test code executes quickly else developers will be ever less-likely to run them as the number of tests grows and the time to execute them becomes prohibitively long.

This is definitely not a license to write poor or sloppy code in your unit tests; I have seen projects where the production code was quite well-written but the unit test code was an abysmal mess that ignored just about every good coding practice of significance.  Since unit tests need to evolve along with the code-under-test during the life of a project, sloppy unit test code will become a productivity hindrance just as surely as sloppy production code in a project of any moderate size.  Its just that along the continuum of quality code, unit test code (in my mind) can be granted a little bit more of a license to be less stringently organized than your production code — its sometimes OK to sacrifice purity of design on the altar of performance in your test code.

Next we are going to create an instance of the results that are going to need to be returned from our call to the methods in the mocked dataprovider.  We will do so and then add two place-holder items into the results so that they appear a little more ‘real’ when the mock dataprovider returns them.    Later we will use Asserts to validate that the results returned from the mocked dataprovider are in fact returned by a very real call to the  PerformSearch() method in our Presenter.

The code that sets up the new mockeResultList item as an IList<PersonSkillSearchView> and then adds two items to it is straightforward…

            List<PersonSkillSearchView> mockresultList = new List<PersonSkillSearchView>();
            mockResultList.Add(new PersonSkillSearchView());
            mockResultList.Add(new PersonSkillSearchView());

That done, we next need to set some expectations on our mock view.  Each of these is basically nothing more than an expectation that the view will be asked to report back to our Presenter the ID (an int) of the selected item in each list of available search criteria items.  Since we are just mocking this behavior, we don’t care what the actual return value is, only that its an integer…

            using (_mocks.Record())
            {
                Expect.Call(view.SelectedPersonTypeId).Return(new int());
                Expect.Call(view.SelectedRegionId).Return(new int());
                Expect.Call(view.SelectedOfficeId).Return(new int());
                Expect.Call(view.SelectedSkillCategoryId).Return(new int());
                Expect.Call(view.SelectedSkillId).Return(new int());
                Expect.Call(view.SelectedSkillLevelId).Return(new int());
                Expect.Call(view.SelectedYearsSinceUsed).Return(new int());
                Expect.Call(view.SelectedYearsUsed).Return(new int());

Now we need to set an expectation on our mocked dataprovider.  Since we know how its supposed to be called by our Presenter (its method GetDistinctPersonsBySearchCriteria() will be invoked in order to interact with the database — though not really since its a mock instance of our dataprovider smile_regular ), we can set the single expectation on the mocked dataprovider as so…

                Expect.Call(provider.GetDistinctPersonsBySearchCriteria(new SearchCriteria())).Return(mockResultList).IgnoreArguments();

Although perhaps a long line of code, this expectation really just says "we expect the dataprovider’s GetDistinctPersonsBySearchCriteria()method to be invoked and passed a SearchCriteria instance and when this happens we want the mock dataprovider to return to the calling Presenter class our mockResultList that we created earlier".

With these expectations in place along with our sample mockResultList for the mock dataprovider to return, this test is merely a matter of creating our presenter instance (using our mock view and mock dataprovider), calling its PerformSearch() method, and Asserting that the presenter’s method returns that values from the mocked dataprovider…

            using (_mocks.Playback())
            {
                PersonSearchCriteriaPresenter presenter = new PersonSearchCriteriaPresenter(view, provider);
                results = presenter.PerformSearch();

                //ensure that the value returned from the presenter is the one that we got back from the call to the dataprovider internal method...
                Assert.AreEqual(mockResultList, results);


            }

image This test ensures that the values returned from the dataprovider’s internal method is correctly being returned from the call to the presenter’s PerformSearch( ) method.

If we again return to our test-with-coverage option in our unit test runner to see how our tests are doing in re: how much of our code is actually being exercised by these tests, we see that our Presenter class is at a nice high 95% coverage, well above the usually-acceptable range of 75-80%.

In fact the only code not tested by this new set of unit tests is the constructor that chains into the constructor we are testing, so we can frankly argue that we have actually attained the usually-impractical 100% code coverage from these tests.  Not bad for a first-pass, eh? smile_wink

Now that this layer of our app is in a known-reliable state, we can (finally) look at building an actual user interface on top of it and that’s where we will go next time~!