Styles of TDD: Left, Right, and Center

Martin Fowler wrote an article called “Mocks Aren’t Stubs” some time ago. In hit he explains the difference between Stubs objects and Mock objects characterizing them both as Test Doubles.

A Stub is designed to provide canned responses. They may also record the number of times a method was invoked or an event fired. Generally they appear in your test assembly as implementations of an interface or a subtype of another concrete type. Mocks, on the other hand, are objects that are setup with call expectations. There similar to a Stub in that canned responses may be offered up to fulfill a testing scenario. The real difference of a Mock is that the expectations get verified after running the actual test code. If all expected calls on the mock were made at least that portion of the test passes.

Hey then goes on to categorize two styles of testing: Classical TDD, and Mockist TDD. The term “Mockist” implies a value judgement, indeed Fowler sites that he prefers the classical style.

Gun Totin’ Conservatives

Classical TDD would have you using principally POCO objects and tests that allow you to reach across multiple classes for in any individual unit test. So, say you have a domain model with Order and OrderLine classes and you’re writing a test to verify that the Order calculates a total by the number of lines in it. Even though the unit under test is the Order class itself, a classical practioner wouldn’t mind bringing in the real OrderLine. If there was some behavior in the OrderLine that interfered with this test you may inherit OrderLine from a stub to fill in with some canned values. If your domain model is POCO enough, generally you could use the original OrderLine without a stub.

The classical style tends to encourage and promote state-based testing, e.g. Assert.IsTrue(myObject.Valid). Though, to be fair, arriving at that state is the product some black-box interaction between the unit under test’s dependencies or should be in a well factored codebase.

Volvo-Driving, Liberal Elites

Mockist TDD focuses on interactions between classes. In this style you have only one class under test, the other classes are built-up through a Mock Objects Framework such as Rhino, NMock2, or TypeMock. These mocked objects tend to be proxy implementations of the interfaces your class under test depend on. Each of these frameworks exposes, in their API, some kind of internal DSL (usually in the form of a fluent interface) by which expectations can be recorded. After you run the code under test there is some method you can call on a mock repository or factory (the object used to build up mocks) to verify that expectations were met.

While this style is heavily focused on interaction between classes there is usually some explicit state-based testing going on. I’ve used most of the popular mocking frameworks and still use NUnit’s asserts quite a bit. Often times the class I am testing will have some responsibility in producing some ultimate state: that it uses its dependencies to get there doesn’t absolve me from having to test relevant state on the class itself.

The Middle of the Road

I was asked by our Lead Developer at Xclaim, Rik, which I considered myself. Instinctively I responded Mockist. After mulling it over for a few days and re-reading the last half of the article I’d now say “a bit of both.” Sometimes I’m in a domain model that’s decoupled from lots of outside dependencies and I prefer the classical, state-based approach. I especially like it for DDD-style Entity and Value Objects patterns. When it gets into DDD-style services that may act on a variety of Entities and take dependency on infrastructure services (database, logging, etc.) I switch to mock mode without really thinking about it.

The main thing about the so-called Mockist style I like is it forces me to slow down and think through the design. Setting up all those expectations is much the same thing as writing down a sequence diagram on your whiteboard. In fact that’s a workflow I am using more often for complex problems.

Before I got hooked on TDD I took a play-dough approach to coding or what Steve McConnell calls “Code Like Hell.” Sure, that works, but you the product you end up isn’t usually that maintainable or well factored. You end up spending LOTS more time in debugging. When following employing TDD, while it seems slower,  you’re minimizing time spent on after-the-fact debugging and leaving a breadcrumb trail for both yourself and others.

The first hurdle I had to get through is the discipline to keep tests small and not to overextend my welcome while in the application code. The classic: “oh let me just do this (which doesn’t have a test) while I’m in here.” Bad Dave. Bad. The next hurdle for me was understanding how mock frameworks work and how to incorporate them into my state/assertion-based only test style. After all this I’d say I’m straddling both sides of the aisle, staying pragmatic, and using the right approach for the situation.

Post a Comment

*Required
*Required (Never published)