Mocking Developments

by Jacob 20. June 2007 16:45

mocking I like unit tests, at least in theory. Having solid unit tests means being able to determine if small changes to a system produce unexpected results much sooner in the development cycle than we could before. The larger your system, the more people developing it, and the longer you expect you'll have to support it, the more useful unit tests are. Like nightly backups or source code control, unit tests are preventative care that has a continuing cost for no immediate, trackable benefit.

The biggest problem with unit testing, though, is being able to test small units of code in isolation from buried dependencies. The typical example of required isolation is when your project is using something like logging or database access (or both). In one of my projects, for example, I have a static Utility class with a CreateLog method that puts an entry into windows' application log. Testing any method that calls this baby is going to be a pain unless I want my application log to fill up with useless test chatter.

Using Mockery to Avoid Undesired Methods

So far, the answer to this tension between complete testing and the side effects of extended dependencies is to use mock objects that stand in for your heavy-weight objects. Mock objects only pretend to do what the actual object does so while your tests think that a log has been created (or a database updated, etc), it actually hasn't.

Unfortunately, the state of the art in mock objects leaves a lot to be desired. Here's what people tell me I would have to do in order to unit test without cluttering up my application log:

  1. Redesign my Utility class so that instead of using a Log object, you can pass it an interface for a log object. This is called "Dependency Injection". More on that later.
  2. Since my Utility class is static, this means I have to either mess with swapping out a singleton or pass the ILog interface into my CreateLog method. Or make it an instanced class, of course.
  3. Use a mock framework to create a special instance of an ILog that doesn't actually do anything except parrot back what you tell it to when certain conditions are met (methods called etc.).
  4. Call the object I'm testing, passing in the ILog instead of whatever it was using before.

Simone Chiaretta gives an excellent example of using Rhino Mocks to mock an NHibernate repository where you can see this technique at work.

Dependency Injection Objection

Here's the thing: Dependency Injection sucks. I don't like it. It exists solely to overcome this weakness of Test Driven Design and it strikes me as a huge kludge for the sake of purity. It intrudes into all aspects of development from design to QA and requires that you re-architect any systems that were created before you got religion. Ick.

Phil Haack had an article yesterday about HttpSimulator, a new project he put together that helps simulate HttpContext objects for unit testing. This is a very clever way to overcome embedded dependencies for a common .Net subsystem without resorting to dependency injection.

Outside of something like Phil's solution, dependency injection seems to be the best way to get full unit test coverage in large projects that have broad effects or latency-prone subsystems, though. I hate having to acknowledge that. Interfaces have their uses and all, but the prospect of creating an interface wrapper for every object I want to skip in unit tests and then having to make sure I can hot-swap important objects using these interface wrappers is a mountain of work just to extend unit tests a little. Blah.

TypeMock to the Rescue

Still, unit tests are important enough that I wanted to try them out on a project or two and see how bad it really is to implement dependency injection and have a project that has 100% unit test coverage. Researching different mock frameworks was depressing, though. There are quite a few of them and they all have the same pattern. I thought I was truly doomed. Then I stumbled across TypeMock.

It looks to me like they've developed a system much like Phil's HttpSimulator, only more general in nature. TypeMock allows you to declare a type (hence the name, I'm guessing), and let your test know that calls to that type are going to bypass the called method altogether. It allows you to check what parameters are being passed in and setup what results will be returned—the kind of things you'd expect a mock object to do for you. All without the dependency injection nonsense. Sweet!

Their professional and enterprise editions even have some cool recorder objects that implement IDisposable and allow you to use extremely clear syntax with fine control over the mocked objects and methods. Those editions run a couple hundred bucks, though, so I'll probably have to give them a pass. Their community edition is free, however, and while the syntax is a bit more involved (and obscure), it still gives you the ability to avoid implementing a plethora of wrapper interfaces. I love that.

Now Wait Just a Doggone Minute

It's not all roses, of course. It looks like in order to work properly, you need to run their TMockRunner.exe program with your unit test framework as a command line argument. I'm thinking this is what enables them to penetrate so deep into your classes. This means that you have some setup to do if you want to integrate TypeMock into your development environment. Still, that's a lot less work that creating a whole new paradigm and then exposing all your dependencies, I'm thinking.

Since I've only just installed TypeMock, I can't tell if it actually does all it claims to do or if it's a buggy piece of crap. For all I know, it's just so much snake oil making promises it cannot actually keep. We'll see about that here shortly.

At any rate, I like what I've seen so far and I really hope it turns out to be as nifty as it looks. I'll post updates here as they occur to me going along.

Tags: , , , , ,

Comments


June 21. 2007 02:41
Haacked
I've heard good things about TypeMocks. I haven't had a chance to use it. I won't use it on an OSS project because it's not free and I don't want to create that barrier to testing.

For client projects, I'll consider it. Thought there is the worry that it will make me lazy in making objects testable. I think there are side benefits to making objects testable. For example, such objects tend to be easy to use. If you can't test it, it might be a bit too complex or obtuse.


June 21. 2007 04:36
Jacob
http://www.typemock.com/Features.htm">TypeMock Community edition is free. It's only if you want the easy syntax of the Natural Mocks or the test attribute decorators that you have to ante up.


February 6. 2008 17:14
Troy DeMonbreun
[... TypeMock seems to offer a shortcut around these interface extractions but some TDDers might feel uncomfortable with the power of such a shortcut as it is incongruent with their valuing of TDD's IoC enforcement....]

Comments are closed

Information

    Recent Posts

    Calendar

    <<  September 2010  >>
    MoTuWeThFrSaSu
    303112345
    6789101112
    13141516171819
    20212223242526
    27282930123
    45678910

    View posts in large calendar
    Disclaimer
    The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

    © Copyright 2010 Scruffy-looking Cat Herder