Advertisements
Posted by: jsonmez | January 23, 2011

Back To Basics: Unit Testing Without Mocks

In my last post, I revealed my conclusions regarding what to do instead of misusing IoC containers and interfaces all over your code mostly for the purpose of unit testing.

One of the approaches I suggested was to focus on writing level 1 or level 2 unit tests and occasionally level 3 unit tests with 1 or possibly 2 dependencies at most.

I want to focus on how this is possible, using real code where I can.

First let’s talk about the approach

When I first talk about writing mainly level 1 or level 2 unit tests, most people assume that I mean to cherry pick the few classes in your code base that already qualify and only write unit tests for those classes.

That is not at all what I am advocating.

Instead, the approach I am suggesting is to find ways to make most of the actual logic in your code become encapsulated into classes that depend mostly on data.

What I mean by this is that our goal should be to refactor or write our code in such a way that logic is grouped into classes that only depend on primitive types and data classes, not other classes that contain logic.

This of course is not fully achievable, because something will have to tie all of these logic containing classes together.  We we need these tie-together classes, but if we can make their job to simply execute commands and tie other classes together, we can feel pretty confident in not unit testing them, and we make our job a whole lot easier.

So to summarize, the basic strategy we are going to employ here is to eliminate the need for mocks by designing our classes to be much smaller, having much tighter roles and responsibilities, and operating on data that is passed in rather than manipulating methods on other classes.

There are many patterns we can use to achieve this goal.  I’ll show you an example, then I’ll try to cover some of the major patterns I have discovered so far.

A real world example

I recently released a Java based Android application called PaceMaker.  When I had started out building this application, I set out with the high and mighty goal of using Google Guice framework for dependency injection and BDD style unit tests using JMock to mock passed in dependencies.  It wasn’t a horrible approach, I wrote about it here.

What I found with this approach though was that I was spending a large amount of time creating mocks, and I wasn’t getting much benefit from it.  So, I had abandoned writing unit tests for the code all together, and I pulled out the now almost useless Guice.

The past couple of nights, I decided to use this project as a test project to demonstrate some of the ideas I have been talking about and thinking about.

I wanted to take my real code, refactor the logic out of it into small classes with little or no dependencies, and write BDD style unit tests that would be simple and easy to understand.

The big challenge here was trying to find a small enough piece of code to use an as example.  For this example, I am going to use a bit of code that I was using to generate the name of a file that I write to disk for saving the data from a run.

This code was originally inside of a presenter class that handled generating a file name to pass to a serializer class in order to serialize the run.

history_detail

Here is the original private method that existed in the presenter.

private String getRunFileName()
{
     String completeFileName = StorageManager.getDataStorageDirectory();
     Location firstLocation = locationTracker
          .getLocations().iterator().next();
     Date firstPointTime = new Date(firstLocation.getTime());

     SimpleDateFormat dateFormat = new
         SimpleDateFormat("MMddyyyy_HHmmss");
     dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
     String fileName = dateFormat.format(firstPointTime) + ".gpx";

     completeFileName = completeFileName + fileName;
     return completeFileName;
}

 

This method was a perfect candidate for some easily testable logic that could be put into its own class, but there are a few problems we should notice here.

  • We are dependent on StorageManager to get the data storage directory used as the base directory.
  • We are dependent on the locationTracker object to get the time of the first location.
  • There is some real logic here in the form of a transformation.  (It is important to note that we are dealing with logic, not just commands, because testing execution of commands is not as important as testing logic.)

My approach to this refactor is actually pretty simple.  The first thing we need to do is see the dependencies for what they are.  It looks like our logic is dependent on StorageManager and locationTracker, but in reality the logic is dependent on the string which is the base directory for the file and the time to use for the file name.

We can change this code to reflect that pretty easily.

 

private String getRunFileName(String baseDirectory, Calendar time)
{
     String completeFileName = baseDirectory;
     SimpleDateFormat dateFormat = new
         SimpleDateFormat("MMddyyyy_HHmmss");
     dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
     String fileName = dateFormat.format(time.getTime()) + ".gpx";

     completeFileName = completeFileName + fileName;
     return completeFileName;
}

What we have done here is small, but it is critical.  We have eliminated dependencies that would otherwise have to be mocked to test this logic.  Sure, we will still need to use those dependencies to get the data to pass into this method, but we can leave that code in the presenter class and move this code into its own class.  The class will be small for now, but it will be easily testable with a level 1 unit test (our favorite kind.)

More examples

I didn’t cherry pick this example from the source code in PaceMaker, but I did cherry pick it for this blog post, because it was one of the shorter examples I could use.

I have several other areas of code in my presenter class in PaceMaker where I used a similar approach to extract out the logic, pull it into its own class with little or no dependencies and write unit tests for.

Here are two other examples:

  • Pulled the state logic for starting, stopping, pausing, resuming and calculating length of time paused during a run into its own class.  I elected to add one dependency (the presenter itself as an observer) to the refactored class in order to allow the class to notify the presenter when the state changed.  In C# I would have just used an event to do this, but in Java we use the observer pattern.
  • Pulled out the logic that created the GPX data files into a GPXDataModelBuilder which instead of depending on the LocationTracker class depended only on the data from that class.

The result ended up being very clear, easy to write, level 1 and level 2 unit tests with no mocking.  In addition, my class structure is now much more tightly cohesive, with a much tighter and clearer responsibility.  Before my presenter was doing several things, but now many of those things are broken up into very small testable classes.

In my next post, I’ll go into the patterns you can use to create classes that are able to be tested by level 1 and level 2 unit tests.

As always, you can subscribe to this RSS feed to follow my posts on Making the Complex Simple.  Feel free to check out ElegantCode.com where I post about the topic of writing elegant code about once a week.  Also, you can follow me on twitter here.
Advertisements

Responses

  1. […] unit testing. One of the approaches I suggested was to focus on writing level 1 or level 2 unit… [full post] jsonmez Making the Complex Simple uncategorized 0 0 0 0 […]

  2. […] This post was mentioned on Twitter by Bruce Onder, Google Rss Reader. Google Rss Reader said: Back To Basics: Unit Testing Without Mocks: In my last post, I revealed my conclusions… http://goo.gl/fb/fd1oA […]

  3. […] Back To Basics: Unit Testing Without Mocks – John Sonmez continues has back to basics series with another post looking at testing. In this post he discusses how you can avoid Interfaces, Inversion of Control and mocks by making more of your tests ‘level 1 or 2′, illustarting the approach with an example. […]

  4. I think you are saying the same as the genius Steven Sanderson
    http://blog.stevensanderson.com/2009/11/04/selective-unit-testing-costs-and-benefits/

    • You are correct, wow, he had me beat to this idea by over a year. His post is excellent! Thanks for pointing this out. Excellent read!

  5. Great post, as usual John!

  6. […] my previous post I talked about unit testing without mocks.  I gave some examples of how I had done this in […]

  7. Good post Jon; I hit something similar this week. I was distracted refactoring a not-quite-a-builder that instantiated a sealed class, just so I could mock out a method call on the sealed class, and was just despairing at the knock on effects when I realised — my dependency isn’t on the builder, it’s on the product. D’oh.

    Looking forward to the patterns you mention at the end, and definitely think the approach is worthwhile!

    • Ack; Jon -> John 🙂

  8. […] abolishing the writing of unit tests.  See my original conclusions post, or my post on unit testing without mocks for a better understanding of what I am advocating in regards to unit […]

  9. good one!
    I can easily collect all your examples of refactoring and assemble a book 😛
    it is amazing how simple the idea is and how rarely I see it in production code 😦

    next step is to keep formatting out and keep it configurable in values.xml 🙂


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

Categories

%d bloggers like this: