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.

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

  5. Sarthak Nigam says:

    Hey Eric,
    You won’t be able to do that if your ClassUnderTest does not have a constructor that accepts the mock or a setter to set the mock, or am I missing something?

  6. Hm… yes, I think this is true. It seems that Mockito will try to inject the property directly if no constructor nor setter is present (see http://docs.mockito.googlecode.com/hg/latest/org/mockito/InjectMocks.html). Do note that, in the case of ambiguity in the types of the dependencies, the injection is happening in a non-obvious fashion.

    For example, this code throws a NullPointerException:

    @RunWith(MockitoJUnitRunner.class)
    public class TestMockito {
    @Mock
    private MyDependency secondDependency;
    @InjectMocks
    private ClassUnderTest instance = new ClassUnderTest();

    @Test
    public void test() {
    instance.doSomething();
    }

    public static class ClassUnderTest {
    MyDependency dependency;
    MyDependency secondDependency;

    public void doSomething() {
    secondDependency.println();
    }
    }

    public static class MyDependency {
    public void println() {
    System.out.println(“Hello world”);
    }
    }
    }

    I’d argue that the very fact that this is not blindingly obvious is an argument in favour of avoiding annotations… and make dependencies obvious by changing the code under test to allow for injection in a normal, manual way. This approach is also very much in the spirit of Mockito: its goal is not really to work with existing code, but rather to guide the creation of new code. Other tools are better at working with existing code bases.

  7. Sarthak Nigam says:

    Yeah they should definitely make it clearer, I recently started working on test cases and was confused for a while for how it worked. Thanks for the info

Leave a Reply

Your email address will not be published.