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 ;).

followme Effective Mockito Part 2

Read the other Effective Mockito posts:

10 Responses to “Effective Mockito Part 2”

  1. Marcel says:

    MockitoJUnitRunner and MockitoAnnotations were new to me! Thanks. I’ll add these two posts to a must-read list for our students ;)

  2. Brian says:

    Tip I recently discovered: if you’re already using a test runner (for example using Spring’s test framework) and can’t use the MockitoJUnitRunner, you can still use the annotations by adding

    MockitoAnnotations.initMocks( this );

    to an @Before method or in your test runner (if you’re using one of your own).

  3. @Marcel, thats pretty awesome. Thanks man.

    @Brian, You are absolutely right. When using another Runner this would be the only option ;)

  4. SeB says:

    That is a very nice introduction to Mokito.
    One comment though, you call the example where you introduce the @before a nice and clean example, but this does not look that way to me.
    I think it is a bad practice to share the same object between test without any king of reset, you may have unexpected side effect due to the use of the object in another test case.
    Fortunately Mokito offers reset method for this purpose (http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html#17) .

  5. Dirk says:

    @SeB: There’s no need to worry. JUnit instantiates a new instance of the class before running each test method. Thus, the mock isn’t really shared by multiple methods.

  6. Patrick says:

    @SeB

    The same object is not being shared between tests. JUnit creates a new instance of the SecondPartTest class per test, and since objectUnderTest and strategy are instance variables, they won’t persiste between test cases.

  7. Frank says:

    @SeB

    As the mockito documenation explains the reset method should only be used if you insert a mock object into a dependency injection container like Spring. Spring reuses context instances for several test methods that share the same context configuration. I think this is done for performance reasons. In such situations there is indeed a need to reset the mock object manually. This can be done e.g. in an @After teardown method of your test case. As Dirk and Patrick have already explained in a plain junit test the mock object created with @Mock will not be shared between the test methods.

  8. Thanks guys for clarifying this ;)

  9. E says:

    If you are using Spring and have autowired private members that you want to mock out, you can use Mockitos WhiteBox.setInternalState(), which can help reduce the need for constructor args or setters in your obect under test. Doesnt reduce code in your test but will reduce code in your object under test which is always a plus

  10. Alex says:

    And don’t forget there’s also an @InjectMocks annotation. It will allow to inject the mocks withaout having to passing them into the constructor or using setters.

    @Mock
    Strategy strategy;

    @InjectMocks
    Something objectUnderTest;

    Since mockito 1.9, it works for constructor arguments as well, previously it only worked if setters existed.

10 responses so far

Written by . Published in Categories: Planet Eclipse