Testing Patterns for Data


Yesterday, I posted about using enums versus a persistent store. I got a comment back from another proponent of TDD and separation of concerns (original post here). I have included the entire comment, as I want to make sure to give credit to the good ideas in the comment and show that my post is not aimed at the comment, but a tangent that popped into my mind. The comment was merely a catalyst for this entry:
 
I’m torn on this issue. In the Visual FoxPro world, we put all kinds of metadata in dbfs. These days, I don’t like putting anything outside the scope of my unit tests. I think the options in the list are the result of user stories, so should live in the application, not the db. Furthermore, putting the metadata in the DB puts it beyond the scope of thorough change management in general, not just unit tests.
 
All I am focusing on here is the "outside of the scope of my unit tests" bit. I am also envisioning what a newbie to TDD might mean if he had stated the same thing, and counter the thought process.
 
With a "normal" testing pattern, like a "normal" development exercise, you often end up with a chain from one end to the other. But, you can solve this problem with dependency injection. While this is relatively new to Microsoft, having released their first application block in this arena last month (The Unit Application Block), mocks have long been a part of unit testing frameworks. Both nunit, a unit test framework ported from Java’s junit, and mbunit have mocks. As an aside, mbUnit uses RhinoMocks, a great open source mock object framework. With the plethora of choices here, there is no reason to go to the database to get enum values, as you do not have to include production values to test.
 
In addition, there are patterns that allow you to easily inject test bits into your code, like the Repository Pattern. You have to think a bit "upside down" to use the patterns (paradigm shift), but there are plenty of examples on the web. In fact, there is a really nice example of the Repository Pattern in Rob Connery’s video series for the MVC Storefront (MVC Framework ECommerce project) – about 2 minutes in he mentions not wanting to go to a database – tres kewl. Here are some links:
 

Here is the basic step by step:

  1. Create an interface – this is primarily to avoid tight coupling. Rob’s interface is
    public interface ICatalogRepository {
        IQueryable<Category> GetCategories();
    }


    NOTE: This gets more complex as time goes on; this is just enough code to set up a test.
    Also note that the design here is to make the interface as simple as possible and still get the word done.
  2. He codes a very basic service (This will actually be coded after the tests, so it is just stubbed) – the idea here is to get the design down before coding. This step is optional, as the service is not used for a few steps.
    public class CatalogService
    {

        public IList<Category> GetCategories() {
           
    throw new NotImplementedException("Write a Test!");
        }
    }

    NOTE: I love the exception message here! Open-mouthed
    This part becomes important soon, but I have included it primarily for the error message.

  3. He creates a test repository class that spits out fake data. This is the main point of this blog entry. I have added some comments to the code so you see what is going on.
    public class TestCatalogRepository : ICatalogRepository {

        public IQueryable<Category> GetCategories()
        {
           
    IList<Category> result = new List<Category>();

            for (int i = 1; i <= 2; i++)
            {
               
    //Create parent object
                Category c = new Category();
                c.ID = i;
                c.IsDefault = i == 1;
                c.Name =
    "Parent" + i.ToString();
                c.ParentID = 0;
                c.Image =
    new CategoryImage("thumb", "full");

                //Create children objects (hierarchy)
                int subCategoryID = 10 * i;
               
    for (int x = 10; x < 15; x++)
                {
                    Category sub =
    new Category();
                    sub.ID = subCategoryID;
                    sub.Name =
    "Sub" + x.ToString();
                    sub.ParentID = i;
                    sub.Image =
    new CategoryImage("thumb", "full");
                    result.Add(sub);
                    subCategoryID++;
                }
                result.Add(c);
            }

            return result.AsQueryable<Category>();
        }
    }

    This might seem like a lot of code to write before tests, but it is actually setting up fake data for the test. Note that this uses the interface ICatalogRepository. Now, let’s get to some testing.

  4. First test is to ensure the Repository Return set is not null
    [TestMethod]
    public void CatalogRepository_Repository_Categories_IsNotNull() {
        ICatalogRepository rep =
    new TestCatalogRepository();
        Assert.IsNotNull(rep.GetCategories());
    }

    Now, if you wanted to test your TestRepository, you would test this method first, but the important thing here is we are making sure our test class is solid before we go to testing the code that will use a repository (our service). We are also testing the test in this case.

  5. Now you add a method to the service to instatiate it with a repository. Baby steps.
    public class CatalogService : Commerce.MVC.Services.ICatalogService
    {
       
    ICatalogRepository _repository = null;
       
    public CatalogService(ICatalogRepository repository)
        {
            _repository = repository;
           
    if (_repository == null)
               
    throw new InvalidOperationException("Repository cannot be null");
        }

        public IList<Category> GetCategories()
        {
           
    throw new NotImplementedException("Write a Test!");
        }
    }
  6. And the test is written like so
    [TestMethod]
    public void CatalogService_Can_Get_Categories_From_Service()
    {
        ICatalogRepository rep =
    new
    TestCatalogRepository();
        catalogService =
    new
    CatalogService(rep);

        IList<Category> categories = catalogService.GetCategories();
        Assert.IsTrue(categories.Count > 0);
    }

  7. Now you fire the test and it fails with a NotImplementedException, as expected. This is the re in red … green … refactor.
    For those who are not into TDD, you might wonder why you force a test to fail first. The best answer I can think of is to ensure you have not aready implemented the code and also to ensure you have not accidentally written something that is already true. As developers are generally over optimistic, this is more important than one might think.
  8. Now we add just enough code for our test to pass.
    public IList<Category> GetCategories()
    {
       
    return _repository.GetCategories().ToList();       
    }
  9. Our test passes, so we go to the next step, which is to test the parent-child relationshps …

I don’t want to transcribe the entire video, so I will quit here, but you should now see that by passing in the object that gets the data, you can make a test object quite easily, without employing depency injection. This pattern is not applicable everywhere, of course, but it works here. You should also note that testing involves methodically going from test to code. Rob’s example might make a purist a bit peeved, but I am fine with working with stubs for your red light condition.

When I said "upside down" earlier, I was speaking of passing the Repository to the service so the service can be tested with more or less "arbitrary" test code. It is also a paradigm shift when one thinks about what is being tested versus where we usually being our code. In so many applications, we start writing the database first or the UI first and we work from end to end. In Rob’s example, you are working on the business logic first and moving outward to the UI and database. There are two benefits to this method:

  1. We are thinking in terms of business needs rather than application needs. This may seem like a subtle distinction, and in many ways it is, but the change in thought pattern is quite profound.
  2. We are working out use cases rather than pages or tables. This is not subtle. We are working the usage of our system first, rather than attempting to bolt on a user experience afterward.
    NOTE: This is what I like to call "use case driven development"

To summarize, there are quite a few ways to avoid going to a database in a unit test. Two mentioned here are mocking the data in a mock object and flipping the pattern so your service takes an object as part of its constructor. I will have to save mocks for another day, as my verbal diarrhea has eaten up all of the time I have to write this post. Crying

Peace and Grace,
Greg

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: