Interfaces and isolation

Roy Osherove has suggested a new name for mocks, fakes, stubs or any test double: Isolation.  True, the myriad of test double names can muddy the language, and Meszaros’ suggested name of “test double” still confuses people that don’t get the “stunt double” comparison.

When I first started using mocking frameworks, before I understood the OO design techniques they were intended to support, I used primarily two methods in Rhino Mocks:

  • MockRepository.CreateMock
  • Expect.Call

Using these two techniques of creating Mock objects and setting expectations, without good OO design, led to a lot of over-specified, brittle tests.  Setting expectations that seemed to mirror the system under test seemed to be rampant duplication and hindrances to change.  Over time, as I started to learn more about good OO design and the SOLID principles, the issues of brittle and over-specified tests simply went away.  Techniques such as:

  • Dependency inversion principle
  • Interface-based design
  • Command-query separation
  • Single responsibility principle
  • Separation of concerns

All led to better specified behavior in my tests.

Which is why the name “isolation” means nothing to me.

When I’m using interface-based design, I’m doing so not because of some innate desire to increase testability, but because I want to separate concerns and invert my dependencies.  I want users of my class to know exactly what is needed for this class to operate.  I employ fanatical refactoring to ensure the names and responsibilities of the classes I create are clear to the maintainers of my application.

If I employ the DIP and interface-based design, what exactly am I isolating my class from?  Interfaces of which the class already doesn’t care which implementation is provided?  Again, I don’t use interfaces solely to swap out a test double in a unit test, but to achieve clear separation of concerns, hone the single responsibility of the class, and invert the dependencies.

When I use Rhino Mocks in the new AAA syntax, I wind up using only three techniques/methods in 99% of cases:

  • MockRepository.GenerateMock to supply my class under test with any dependencies it needs to work
  • Stub extension method to control indirect inputs
  • AssertWasCalled extension method to verify indirect outputs

Following these rules helps me describe very clear behavior in my tests, with obvious results for those reading the tests.  I don’t need to isolate when I’m already depending upon abstractions.

TDD design trade-offs and junk food