/ MOCKITO

The danger of @InjectMocks

Last week, I wrote about the ways to initialize your Mockito’s mocks and my personal preferences. I’m still working on my legacy project, and I wanted to go deeper into some Mockito’s feature that are used.

For example, Mockito’s developers took a real strong opinionated stance on the design: Mockito can only mock public non-final instance methods. That’s something I completely endorse. To go outside this scope, you’d have to use PowerMock (which I wrote about a while ago). That’s good, because for me, spotting PowerMock on the classpath is a sure sign of a code smell. Either you’re using a library that needs some design improvement…​ or you code definitely should.

However, I think Mockito slipped some dangerous abilities in its API, akin to PowerMock. One such feature is the ability to inject your dependencies’s dependencies through reflection. That’s not clear? Let’s have an example with the following class hierarchy:

Sample class diagram

Rules of unit testing would mandate that when testing ToTest, we would mock dependencies DepA and DepB. Let’s stretch our example further, that DepA and DepB are classes that are:

  • Out of our reach, because they come from a third-party library/framework
  • Designed in a way that they are difficult to mock i.e. they require a lot of mocking behavior

In this case, we would not unit test our class only but integration test the behavior of ToTest, DepA and DepB. This is not the Grail but acceptable because of the limitations described above.

Now let’s imagine one more thing: DepA and DepB are themselves dependent on other classes. And since they are badly designed, they rely on field injection through @Autowiring - no constructor or even setter injection is available. In this case, one would have to use reflection to set those dependencies, either through the Java API or some utility class like Spring’s ReflectionTestUtils. In both cases, this is extremely fragile as it’s based on the name of the attribute:

DepA depA = new DepA();
DepX depX = new DepX();
DepY depY = new DepY();

ReflectionTestUtils.setField(depA, "depX", depX);
ReflectionTestUtils.setField(depA, "depY", depY);

Mockito offers an easy alternative to this method: by using @InjectMocks, Mockito is able to automatically inject mocked dependencies that are in context.

@RunWith(MockitoJUnitRunner.class)
public class Test {

    @InjectMocks private DepA depA = new DepA();
    @Mock private DepX depX;
    @Mock private DepY depY;
    // tests follow
}

Since depX and depY are mocked my Mockito, they are in context and thus can automatically be injected in depA by Mockito. And because they are mocks, they can be stubbed for behavior.

There are a couple of drawbacks though. The most important one is that you loose explicit injection - also the reason why I don’t use autowiring. In this case, your IDE might report depX and depY as unused. Or even worse, changes in the initial structure of DepA won’t trigger any warning for unused fields. Finally, as for reflection, those changes may result in runtime exceptions.

The most important problem of @InjectMocks, however, is that it’s very easy to use, too easy…​ @InjectMocks hides the problems of both fields injection and too many dependencies. Those should hurt but they don’t anymore when using @InjectMocks. So if applied to dependencies from libraries - like depA and depB, there’s no choice; but if you start using it for your own class aka ToTest, this for sure seems like a code smell.

Nicolas Fränkel

Nicolas Fränkel

Nicolas Fränkel is a Developer Advocate with 15+ years experience consulting for many different customers, in a wide range of contexts (such as telecoms, banking, insurances, large retail and public sector). Usually working on Java/Java EE and Spring technologies, but with focused interests like Rich Internet Applications, Testing, CI/CD and DevOps. Currently working for Exoscale. Also double as a teacher in universities and higher education schools, a trainer and triples as a book author.

Read More