Monday, February 27, 2012

Mocking Best Practices

When writing unit tests you have to use mocks or stubs for dependant objects. Very often it is convenient to use a mocking library (like RhinoMocks for .NET or jMock for Java). Just using a mocking library does not guarantee to get readable and maintainable unit tests. It make sense to have a set of rules which are guiding developers when writing unit tests with mock objects. I compiled a list of such best practices for mock objects ("mocking" rules). I use the term mock object for a objects verifying expectations about calls to themselves. Test stubs are only used for feeding inputs into the system under test.

Rule 1: Try to avoid using mock objects and prefer state verification over behaviour verification if it is possible.

If you can verify the outcome of an method by checking the return value or by checking the state of the system under test, this is the preferable method, because it is simpler and makes your test more independent from the implementation details. You may need test stubs to feed indirect inputs into the system under test.

Rule 2: Apply the Law of Demeter („no train wrecks”) to your code you want to unit test as much as possible.

Testing code like "employee.GetDepartment().GetManager().GetOffice().GetAddress().GetZip()" is much harder than "employee.GetManagersOfficeZipCode()".

Avoiding "train wrecks" reduces the number of mocks and stubs you need and therefore improves readability and maintainability for your tests.

Rule 3: Use a minimum number of mock objects per test, preferable is only one mock object.

Concentrate on one aspect per test. A reader can identify the most important part more easily. In one test you may check the call to one depended-on component (DOC) and in another test you will check another DOC. You may need additional test stubs to feed indirect inputs into the system under test.

Rule 4: Define a minimum number of expectations as possible.

It’s easier for the reader to see what is important. Tests are less brittle when code changes. Test what code does, not how.

Rule 5: Use Command-Query Separation (Side-Effect-Free Functions) for your code. Don't define expectations on mock objects for queries, only for commands.

Divide all object's methods of your code into two sharply separated categories:

  • Queries: Return a result and do not change the observable state of the system (are free of side effects).
  • Commands: Change the state of a system but do not return a value.
Queries deliver input for tests, commands are output. Only check the output (what)

Rule 6: At the borderline between your own code towards foreign code, it may be wise to not stub or mock the foreign code directly.

Very often it is better to create an own interface and implement a small layer of adapter code. Test this small layer with integration tests including the foreign code. It is much easier then to stub or mock your own adapter interface when you test your other own code. Examples for foreign code are database access code (like ADO.NET, JDBC in Java, Hibernate, NHibernate), active directory access, network access, and so on.


No comments: