Effective Mockito Part 2
As promised in the first part of the “Effective Mockito” blog series, I will concentrate on Mockito specifics in the followup posts. So, the main topic for Part 2 is Mockito’s @Mock
Annotation.
When I write tests I try to follow an explicit pattern, called the build-operate-check pattern. This was described by Uncle Bob in his book “Clean Code” (Page 127, Chapter 9). The main idea behind this pattern is that you try to split your test method into three parts. The first part sets up the environment, the second executes the method you want to test and the third part verifies the expected. You can also apply this pattern with Mockito using the @Mock
Annotation.
When writing tests we often reach a point where we need a second object to get an object under test to work. That’s where we can use mocks :). The test code looks roughly like this:
public class SecondPartTest {
@Test
public void testSomething() {
Strategy strategy = mock( Strategy.class );
Something objectUnderTest = new Something( strategy );
objectUnderTest.doSomething();
verify( strategy ).doSomethingConcrete();
}
}
As you can see we created an object of the type Something
. This object needs another object of the type Strategy
in its constructor and I decided to use a mock for this. After this we execute the method we want to test which is called doSomething
. The doSomething
method should invoke the method doSomethingConcrete
on the object we passed in the constructor. As you’ve probably noticed, it’s the strategy pattern. I chose this one because it’s a perfect fit for the use of mocks. In the last step of the test we verify that the method doSomethingConcrete
was invoked. Nothing special here.
It looks like a nice and clean little test to me. But, in most cases we have more than one test method in a test class. When a new test method is added, it could look like this:
public class SecondPartTest {
@Test
public void testSomething() {
Strategy strategy = mock( Strategy.class );
Something objectUnderTest = new Something( strategy );
objectUnderTest.doSomething();
verify( strategy ).doSomethingConcrete();
}
@Test
public void testDelegateSomething() {
Strategy strategy = mock( Strategy.class );
Something objectUnderTest = new Something( strategy );
when( strategy.doValidate() ).thenReturn( true );
boolean isValid = objectUnderTest.validate();
assertTrue( isValid );
}
}
At this point our nice and clean little test is no longer as nice or clean. By adding one test method we introduced two redundant lines of code, the object instantiation and the mocking. This is a sign that we need to use fields for both the objectUnderTest
and the mock, and create them in the @Before
method as in this snippet:
public class SecondPartTest {
Strategy strategy;
Something objectUnderTest;
@Before
public void setUp() {
strategy = mock( Strategy.class );
objectUnderTest = new Something( strategy );
}
@Test
public void testSomething() {
objectUnderTest.doSomething();
verify( strategy ).doSomethingConcrete();
}
@Test
public void testDelegateSomething() {
when( strategy.doValidate() ).thenReturn( true );
boolean isValid = objectUnderTest.validate();
assertTrue( isValid );
}
}
This makes our test methods clean again, yippee :). But I think we can do better. Mockito provides MockitoAnnotations and I’d like to use one of them in our test. It’s called @Mock
(surprise). Using this annotation we can tell a field that it is a mock. It can look like this:
public class SecondPartTest {
@Mock
Strategy strategy;
Something objectUnderTest;
@Before
public void setUp() {
MockitoAnnotations.initMocks( this );
objectUnderTest = new Something( strategy );
}
@Test
public void testSomething() {
objectUnderTest.doSomething();
verify( strategy ).doSomethingConcrete();
}
@Test
public void testDelegateSomething() {
when( strategy.doValidate() ).thenReturn( true );
boolean isValid = objectUnderTest.validate();
assertTrue( isValid );
}
}
This has at least one major benefit. You can see that a field is a mock at first glance without reading the setUp
method. However, we didn’t save any lines in the setUp
method because we need to tell Mockito to instantiate the @Mock
annotated fields. This looks really ugly because we are mixing Mockito framework code with our test code. We need to find another way to instantiate the mocks. Luckily, Mockito helps out once again.
Since JUnit4 you can choose specific test runners for test classes. You probably know this because you use it in your TestSuite classes all the time. Anyway, Mockito provides a runner called MockitoJUnitRunner
. Using the runner looks like this:
@RunWith( MockitoJUnitRunner.class )
public class SecondPartTest {
@Mock
Strategy strategy;
Something objectUnderTest;
@Before
public void setUp() {
objectUnderTest = new Something( strategy );
}
@Test
public void testSomething() {
objectUnderTest.doSomething();
verify( strategy ).doSomethingConcrete();
}
@Test
public void testDelegateSomething() {
when( strategy.doValidate() ).thenReturn( true );
boolean isValid = objectUnderTest.validate();
assertTrue( isValid );
}
}
As you can see we could remove the initMocks
call in the setUp
method and we are nice and clean again. And, that’s how you can get to a clean test using the @Mock
annotation. In the next Effective Mockito installment I’ll show you how spies can be used to get to a clean test when you depend on third party libraries ;).
Read the other Effective Mockito posts: