Test Doubles: mocks, dummies and stubs
Most classes haveĀ collaborators. When unit testing, you usually want to avoid using real implementations of those collaborators to avoid test brittleness and binding/coupling, and instead use Test Doubles:Ā Mocks, Stubs and Doubles. This article referencesĀ two existing articles on the subject:Ā Mocks Arenāt Stubs, by Martin Fowler andĀ The Little Mocker, by āUncleā Bob Martin. I recommend them both.
Terminology
I am going to borrow aĀ term fromĀ Gerard Meszarosās bookĀ xUnit Test Patterns. In it, he introduces the termĀ System Under Test (SUT), that is, theĀ thing weāre testing.Ā Class Under Test is an alternative that is more applicable in the Object OrientedĀ world, but Iāll stick with SUT since Fowler also does.
I will also use the terms state verification and behavior verification. State verification is verifyingĀ code worked correctly by examining the state of the SUT or itās collaborators. Behaviour verification is verifying that collaborators were called or invoked in the way we expected.
Test Doubles
OK, back to how to deal with collaborators of the System Under Test. For each collaborator of the SUT, you could use theĀ real implementation of that collaborator. For example, if you have a Service that collaborates with a Data Access Object (DAO), as in the WidgetService example below, you could use the real DAO implementation. However,Ā it very likely goes against a database, which is definitely not what we want for a unit test. Also, if the code in the DAOĀ implementation changed, it could cause our test to start failing. I personally do not like tests starting to fail when the code under test itselfĀ did not change.
So, instead we can use what are sometimes called Test Doubles. The term Test Doubles also comes from MeszarosāsĀ xUnit Test PatternsĀ book. He describes them as āany object or component that we install in place of the real component for the express purpose of running a testā.
In this article, I will cover the three main types of test doubles that I use: Mocks, Stubs and Dummies. I will also briefly cover two that I rarely explicitly use: Spies and Fakes.
1. Mocks
First, āmockā is an overloaded term. ItĀ is often used as an umbrella term for any test double; that is,Ā any type of object used as a replacement for a real collaborator in a class under test. I am comfortable with this since most mocking frameworks support most of the test doubles discussed here. But, for the purposes of this article, I will use mock in its stricter, more limitedĀ meaning.
Specifically, a mockĀ is a type of test double which usesĀ behavior verification.
Martin Fowler describes mocksĀ as āobjects pre-programmed with expectations which form a specification of the calls they are expected to receiveā. Where asĀ Uncle Bob says that a mock spies on the behavior of the module being tested and knows what behavior to expect. An example may make it clearer.
Imagine this implementation of aĀ WidgetService:
public class WidgetService {
final WidgetDao dao;
public WidgetService(WidgetDao dao) {
this.dao = dao;
}
public void createWidget(Widget widget) {
//misc business logic, for example, validating widget is valid
//...
dao.saveWidget(widget);
}
}Our test might look something like this:
public class WidgetServiceTest {
//test fixtures
WidgetDao widgetDao = mock(WidgetDao.class);
WidgetService widgetService = new WidgetService(widgetDao);
Widget widget = new Widget();
@Test
public void createWidget_saves_widget() throws Exception {
//call method under test
widgetService.createWidget(widget);
//verify expectation
verify(widgetDao).saveWidget(widget);
}
}We created a mock of WidgetDao, and verify that it was called as we expected. We could also have told the mock how to respond when it was called; this is a big part of mocks, allowing you to manipulate the mock so you can test a specific unit of your code, but in this case it isnāt necessary for the test.
Mocking Frameworks
In this example, I am using Mockito for the mocking framework, but there are others in the Java space too, including EasyMock and JMock.
Roll-your-own mocks?
Note that you donāt have to use mocking frameworks to use mocks. You can write mocksĀ yourself too, and even build theĀ assertion in to the mock.Ā In this case for example, we could create a class calledĀ WidgetDaoMock that implements theĀ WidgetDao interface, and whose implementation of theĀ createWidget() method simply records that it was invoked. You can then verify the call was made as expected. Still, modern mocking frameworks make this kind of roll-your-own solution largely redundant.
2. Stub
A stub is an object that āstubs outā, or provides a greatly simplified version of, the implementation for the purposes of testing.
For example, if our WidgetService class now also relies on aĀ ManagerService also. See theĀ standardize method here:
public class WidgetService {
final WidgetDao dao;
final ManagerService manager;
public WidgetService(WidgetDao dao, ManagerService manager) {
this.dao = dao;
this.manager = manager;
}
public void standardize(Widget widget) {
if (manager.isActive()) {
widget.setStandardized(true);
}
}
public void createWidget(Widget widget) {
//omitted for brevity
}
}And we want to test that the standardize method āstandardizesā a widgetĀ when the manager is active, we could use a stub like this:
public class WidgetServiceTest {
WidgetDao widgetDao = mock(WidgetDao.class);
Widget widget = new Widget();
class ManagerServiceStub extends ManagerService {
@Override
public boolean isActive() {
return true;
}
}
@Test
public void standardize_standardizes_widget_when_active() {
//setup
ManagerServiceStub managerServiceStub = new ManagerServiceStub();
WidgetService widgetService = new WidgetService(widgetDao, managerServiceStub);
//call method under test
widgetService.standardize(widget);
//verify state
assertTrue(widget.isStandardized());
}
}Where as mocks are generally used for behavior verification, stubs can be used for eitherĀ state or behavior verification.
This example is very basic, and could have been done using a mock too, but stubs can provide a useful approach for test fixtureĀ configurability. We could have parameterizedĀ ManagerServiceStub so that it takes a value for the āactiveā field as a constructor argument and hence can be reused for the negative test case.Ā More complex parameters and behaviors can be used too. Other options are creating the stub as an anonymous inner class, or creating a base classĀ for the stub, such as ManagerServiceStubBase, for others to extend. The advantage of the later is that should the ManagerService interface change, only the ManagerServiceStubBase class will break and needs to be updated.
I tend to use stubs a lot. I like to flexibility they provide in being able to customize the test fixture and the clarity they provide from being plain olā Java code. No need for the future maintainers to be able to understand a certain framework. Most of my colleagues seem to prefer using a mocking framework. Find what works for you and use your best judgement.
3. Dummy
As the name implies, a dummy is a very dumb class. It contains next to nothing, basically just enough to get your code to compile. You pass a dummyĀ into something when you donāt care how itās used. e.g. as part of a test, when you must pass an argument, but you donāt expect theĀ argument toĀ be used.
For example, in the standardize_standardizes_widget_when_active() test in the previous example, we still continued to use the mocked WidgetDao. A dummy may be a better choice since we never expect the WidgetDao to be used at all in the createWidget() method.
public class WidgetServiceTest {
Widget widget = new Widget();
class ManagerServiceStub extends ManagerService {
@Override
public boolean isActive() {
return true;
}
}
class WidgetDaoDummy implements WidgetDao {
@Override
public Widget getWidget() {
throw new RuntimeException("Not expected to be called");
}
@Override
public void saveWidget(Widget widget) {
throw new RuntimeException("Not expected to be called");
}
}
@Test
public void standardize_standardizes_widget_when_active() {
//setup
ManagerServiceStub managerServiceStub = new ManagerServiceStub();
WidgetDaoDummy widgetDao = new WidgetDaoDummy();
WidgetService widgetService = new WidgetService(widgetDao, managerServiceStub);
//call method under test
widgetService.standardize(widget);
//verify state
assertTrue(widget.isStandardized());
}
}In this case, I created an inner class. In most cases, since the Dummy functionality rarely changes across tests, it makes more sense to create a non-inner class and reuse for all tests.
Also note in this case that using a mocking framework to create a mock instance of the class is also a viable alternative. I personally rarely use dummies and instead create mocks like this:
WidgetDaoDummy widgetDao = mock(WidgetDao.class);
Although admittedly it can be more difficult to throw exceptions whenĀ unexpected invocations do happen (it depends on your mock framework of choice), it does have the big advantage of brevity. Dummies can be long since they need to implement every method in the interface.
As with Stubs, Dummies can be used with either state or behavior verification.
Spies and Fakes
I shall briefly cover two other types of test doubles: Spies and Fakes. I say briefly because I personally rarely use these two types of doubles explicitly myself, but also because terminology can be confusing enough without introducing more nuances! But in the interest of completenessā¦
Spy
You use a Spy when you wanted to be sure that a method was called by your system. It can also record all kinds of things such counting the number of invocations, or keeping a recordĀ of the arguments passed in each time.
With spies though, there is a danger of tightly coupling your tests to the implementation of your code.
Spies are used exclusively used forĀ behavior verification.
This type of functionality is alsoĀ very well covered by most modern mocking frameworks.
Fakes
Martin Fowler describes fakes as follows:Ā Fakes have working implementations, but usually take some shortcut which makes them not suitable for production (an in memory database is a good example).
I personally rarely if ever use them.
Conclusion
Test Doubles are an integral part of unit testing. Mocks, Stubs and Doubles are all useful tools to have, and understanding the difference is important.
A mock in the strictest sense of the word is simply a double that uses behavior verification; that is expectations on a double are specified and then verified when the SUT is called. However, the work mock has also grown to more generally describe any of the doubles described here, and indeed most modern mocking frameworksĀ can be used in that general way.
Finally, which type of double should you use? It depends on the code under test, but I recommend being guided by whatever makes the intent of your tests clearest.
Sources
- Mocks Arenāt Stubs, by Martin Fowler
- The Little Mocker, by āUncleā Bob Martin
- xUnit Test Patterns, byĀ Gerard Meszaros
| Reference: | Test Doubles: mocks, dummies and stubs from our JCG partner Shaun Abram at the Shaun Abram blog blog. |

