I've never paid much attention to what mocking framework I use. I've used EasyMock and JMock, I observed no big difference between the two really. Recently, I started to change some existing JMock unit tests to use Mockito instead. It seemed to have a more elegant interface, and it turned out this had other implications on my tests than mere syntactic sugar. It actually gave some new insight on the subject.
A little toy code to illustrate this:
public interface GreetingFormula {
String formula();
}
public class Greeting {
private GreetingFormula gf;
public Greeting(GreetingFormula gf) {
this.gf = gf;
}
public String greet(String name) {
return gf.formula() + " " + name;
}
}
In my Unit Test for Greeting
, I want a Mock
object for the GreetingFormula
interface. I want to verify that formula()
has been actually called on the Mock
object, and also want some return value for the method. A JMock
implementation would look like this:
public class GreetingTest {
private final static String formulaText = "Hello";
private final static String name = "Mr. Doe"
private final static String expectedGreeting = "Hello Mr. Doe";
private Mockery mockingContext;
private GreetingFormula greetingFormula;
private Greeting greeting;
@Test
public void greetPutsNameIntoFormula() {
mockingContext.checking(new Expectations() {
{
one(greetingFormula).formula();
will(returnValue(formulaText));
}
});
Assert.assertEquals(expectedGreeting, greeting.greet());
}
@Before
public void setUp() {
mockingContext = new JUnit4Mockery();
greetingFormula = mockingContext.mock(GreetingFormula.class);
greeting = new Greeting(greetingFormula);
}
}
The solution may look ok at first glance, but there is a subtle issue here. In expectations, two very different concepts are mixed together: how the mock
object should behave (return the right value), and what should be verified on the mock
object afterwards (it has been called exactly once). Let's take a look at how the same task is done using Mockito.
public class GreetingTest {
private final static String formulaText = "Hello";
private final static String name = "Mr. Doe"
private final static String expectedGreeting = "Hello Mr. Doe";
private GreetingFormula greetingFormula;
private Greeting greeting;
@Test
public void greetPutsNameToFormula() {
when(greetingFormula.formula()).thenReturn(formulaText);
assertEquals(expectedGreeting, greeting.greet());
verify(greetingFormula).formula();
}
@Before
public void setUp() {
greetingFormula = mock(GreetingFormula.class);
greeting = new Greeting(greetingFormula);
}
}
Mockito enforces the clear separation of the concepts of mock
object behavior and verification by its design, there is simply no other way of doing it. This might not look like a big deal - on a simple example like this - but in fact it is. Unit test code with a lot of mockery does gain a lot of clarity simply by expressing these steps in the right order:
- Mock behaviour
- Perform test
- Mock verification