Avoid annotations with Mockito

On the Mockito mailing list and on Stackoverflow, there are a significant number of questions that actually reveal that the person asking did not perfectly understand what the Mockito annotations do. Indeed, the annotations are rather magical and their behavior is definitely not obvious.

Since they are mostly syntactic sugar (although whether they actually improve readability is debatable), my recommendation is to do without them entirely. Here are a few examples.

Chaplin

The most common issue is when using @Mock:

@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
	@Mock
	private MyDependency dependency;
	private ClassUnderTest instance = new ClassUnderTest(dependency);
}

Here, the issue us that @Mock is read by Brice Dutheil MockitoJUnitRunner only after the test class is instantiated, that is, after the ClassUnderTest is instantiated. So ClassUnderTest only received a null value, not the mocked dependency.

A fix/variant uses the @InjectMock annotation:

@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
	@Mock
	private MyDependency dependency;
	@InjectMocks
	private ClassUnderTest instance = new ClassUnderTest();
}

This one is more tricky. Although it will work in simple cases, it tends to behave strangely in more complex classes, as pointed out by in a recent thread on the Mockito mailing list: “since 1.9.5, mocks created by Mockito.mock() will be included in the list of injection candidate; that does explain that the mock of ClassToInjected is injected in itself somewhere in an upper class.”
We should also note that it discourages dependencies as final attributes, which is not a good thing.

My preference would be to write something like that:

public class MyClassTest {
	private MyDependency dependency = mock(MyDependency.class);

	private ClassUnderTest instance = new ClassUnderTest(dependency);
}

Yes, there are some redundancies (in the names of the dependency class), but I believe this much is acceptable in a test.

Other available annotations include @Spy and @Captor, which behave in a way similar to @Mock. However, since spies and captors should be used sparingly, to say the least, there are few cases when it makes sense to declare them in the attributes section. Intentions are a lot clearer when spies and argument captors are instantiated within methods anyway.

In summary, the benefits provided by the annotations provided by Mockito do not seem to justify the reduction in readability. I recommend avoiding them.

About Eric Lefevre-Ardant

Independent technical consultant.
This entry was posted in java. Bookmark the permalink.

4 Responses to Avoid annotations with Mockito

  1. Hi Eric

    You may appreciate to use http://docs.mockito.googlecode.com/hg/org/mockito/MockitoAnnotations.html#initMocks%28java.lang.Object%29 in your setUp method in order to control the injection, or create a junit rule to do that.
    Does this would do the right thing in the desired order or i missed something ?

  2. Certainly, but I am not happy with how the resulting code reads. Having a setUp() method just for calling initMocks() does not seem very desirable to me.

    Every time I can, I avoid creating a setUp() method, as it makes harder to follow the flow of the test.

  3. So here is the rule:

    package my.package;

    import org.junit.rules.TestWatchman;
    import org.junit.runners.model.FrameworkMethod;
    import org.mockito.MockitoAnnotations;

    public class MockitoJUnitRule extends TestWatchman { // depends on JUnit Version
    private final Object testObject;

    public MockitoJUnitRule(final Object testObject) {
    super();
    this.testObject = testObject;
    }

    @Override
    public void starting(final FrameworkMethod method) {
    MockitoAnnotations.initMocks(testObject);
    }
    }

  4. Well, a Rule is used via an annotation, right? That rather defeats the purpose of my post ;-)

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>