Saturday, January 21, 2006

Mocking Correctly

A really great posting, "Best and Worst Practices for Mock Objects" lists a number of best practices for mocking.

  • "Be careful about mocking or stubbing any interface that is outside your own codebase. If you don’t truly understand the semantics and proper usage of an interface you don’t have any business mocking that interface in a unit test. My best advice is to create your own interface to wrap the interaction with the external API classes."
  • "My advice is to just test the data access code against the actual database with integration tests. For the most part I think testing persistence code without the database is a complete waste of time."
  • "I’ve worked with some people before that felt that there should never be more than 1-2 mock objects involved in any single unit test. I wouldn’t make a hard and fast rule on the limit, but anything more than 2 or 3 should probably make you question the design...Minimizing the number of mock objects necessary for any given unit test is a very effective way of keeping the Cyclomatic Complexity of your classes below an acceptable level."
  • "Ideally you only want to mock the dependencies of the class being tested, not the dependencies of the dependencies. From hurtful experience, deviating from this practice will create unit test code that is very tightly coupled to the internal implementation of a class’s dependencies."

A few more occurred to me:
  • Use as many patterns and idioms in your unit tests that you do in regular code, like testing exceptions and fixtures. This can be a great way to reduce the drudgery of testing bean objects for instance (not that I in anyway condone the use of bean objects).
  • Allow reuse of commonly used objects between tests.
  • The length and complexity of a unit tests is an indication of the complexity of the underlying object - once a test reaches a certain length/complexity it's time to refactor the object being tested.
  • Duplication in tests is just as bad as duplication in the code being tested.
  • No code goes into production just for the sake of testing.
  • Use reflection to gain access to internal object state. This is related to the previous point as a way to avoid artifacts of testing in production code. Other ideas include a good equals method, package level access and getter methods - but these leave code that may only exist for testing. And the last two are also a good way to break encapsulation.
  • Something that is easy to test is not always good design. For instance, having a fixture or utility code that makes bean objects easy to test drive shouldn't dictate using bean objects for everything.

The previous post in the series, "Why and When to Use Mock Objects" lists what makes a good unit test including: being atomic, order independent and isolated, intention revealing, easy to setup (a unit test code smell is a lot of setup code) and runs fast.

There also looks like a really interesting site, Test Automation Patterns. It lists test code smells including: test code duplication is bad, obscure tests, and data sensitivity. Also, a list of fixture strategies: standard, fresh and shared.
Post a Comment