Menu

Search

Use Mocks Sparingly

Whether I write my tests in the classical style or the mockist style, I always find that my tests are higher quality when I avoid mocks. Some people must be thinking, “how can you use mockist style without mocks?” Well it turns out there’s actually a very strict definition of what a mock is and a lot of developers usually use the word incorrectly. The best definitions I’ve found are from Martin Fowler’s article titled, Mocks Aren’t Stubs. To quote the article:

Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists.

Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an in memory database is a good example).

Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what’s programmed in for the test. Stubs may also record information about calls, such as an email gateway stub that remembers the messages it ‘sent’, or maybe only how many messages it ‘sent’.

Mocks are what we are talking about here: objects pre-programmed with expectations which form a specification of the calls they are expected to receive.

I’m using these definitions when I say that you should avoid mocks in your tests. When I mock objects in Java, I’m often using a library named Mockito. If you write a test like this, you know you’re using a mock:

The clear giveaway here is the verify keyword. I avoid this whenever I can and consider it a smell. In this example the verify checks that the mockedList is cleared if you call the doStuffAndReturnList method on subject.

Here’s why I don’t like this: I do not get the confidence I want from this test. Lets say I want the mockedList to be cleared after I call doStuffAndReturnList(). How do I know that something isn’t added to the list afterclear is called? Well, you can use mocks to verify this, too:

verify(mockedList, never()).add(anyObject());

All good? Well the problem is there are many ways to add an element to a list. Maybe the set method was used instead and your test isn’t catching that. In other words, the way that the mockedList is used inside the subject should be an implementation detail. But, once you use a mock (as opposed to a stub) these details are now exposed.

Rather than testing how the subject’s dependencies are implemented, I instead check that the subject works the way I expect. This gives me the freedom to populate the list any way I choose but know that it’s empty after doStuffAndReturnList() is called.

There are some exceptions to this rule that I practice. Once in a while I will create a method that returns void but I really want to make sure it’s called in a test. An example is testing that a validate method is called that throws an exception. This is a rare occurrence.

What I like about avoiding mocks is my code ends up being more “functional” in style. I pass in parameters to a function and assert that the results look the way I expect. The implementation details are hidden from the test, even if I’m practicing mockist style TDD.