Test behaviour, not your implementation

Quite often I see unit tests that seem very interested in a class’s inner workings. This not only misses the point of a unit test, but makes the class harder to refactor, since the corresponding unit test will have to change more often as well.

Suppose you have a BookService class, responsible for retrieving and storing books:

Pretty straightforward, right? Now, suppose we write a unit test to test the getAllBooks method, using Mockito to stub things out. Often I encounter something like this:

Notice the verify call at the end of the method. This makes assumptions about the class’s inner workings. Don’t do this. A unit test should check if a class implements its contract. Instead, verify behaviour only:

Of course you need a collaborator to get this class going, hence the BookRepository mock object and the recorded behaviour using when.

Verfiy behaviour only also applies to methods that mutate the system (a “command”), like the createBook method in the example class. Of course, such methods have a void result type (if you build your system CQRS-wise, of course). Only difference is, the output comes from the bottom this time (pun intended):

In some cases, a command also has a result type, for example, the result of the mutation. For example, the createBook method could have returned its Book parameter enriched with an id, for example, as a result of storing the book in the repository. In that case, you could verify output at both sides, although assertion the return value only would still be preferred.

Most of the time, however, encountering such a method is probably a side effect anti-pattern and should be refactored into two separate methods.

This entry was posted in Coding. Bookmark the permalink.

Leave a Reply

Your email address will not be published.