Let me explain the problem first. We have a Java class under test. We are using Junit with Mockito framework to write the unit test cases.
We have annotated our test class with @InjectMocks annotation as below:
@InjectMocks private TestClass testClass; @Mock private Dependency1 dependency1; @Mock private Dependency2 dependency2;
That should inject mocked dependencies to the testClass instance. But even after this, when we call a test method like below, we get java.lang.NullPointerException for a mocked dependency. In the below example dependency2 object is null.
@Test public void testAutoVerifyEmailWhenInternalAPICall() { when(dependency2.get(1)).thenReturn(1); testClass.get(1); }
It can happen if you have mixed various dependency injections. It basically means some properties are injected via Constructor injection, some via Property setter injection & others via Field injection.
For example, our actual class under test can look like below:
public Class TestClass{ private Dependency1 dependency1; @Inject private Dependency2 dependency2; @Inject public TestClass(Dependency1 dependency1){ this.dependency1 = dependency1; } ... }
It has dependency1 object which is injected via constructor & dependency2 object which is injected via Field injection. Now we need to understand how @InjectMocks annotation works at a high level. @InjectMocks can’t mix different dependency injection types. It will search for & execute only one type of dependency injection (either Constructor injection, Property setter injection or Field injection in the given order). So if Constructor injection is present as in our example, only the dependencies used in Constructor injection will be injected by @InjectMocks (in our case it is dependency1 object). Any other field which was injected via Property Setter or Field injection will have null value.
That’s why we were getting java.lang.NullPointerException for dependency2.get(1) method. It is a Field injection & so dependency2 object was set to null.
Ideally if we have constructor to initialize an object, that constructor should properly take care of initializing all required dependencies. If it is our own class we could have solved the problem using default constructor (removing the Constructor injection) & adding both fields via Field injection.
public Class TestClass{ @Inject private Dependency1 dependency1; @Inject private Dependency2 dependency2; ... }
Or we could have initialized both fields via Constructor injection as below:
public Class TestClass{ private Dependency1 dependency1; private Dependency2 dependency2; @Inject public TestClass(Dependency1 dependency1, Dependency2 dependency2){ this.dependency1 = dependency1; this.dependency2 = dependency2; } ... }
In case, it is a third-party class or we are not allowed to modify the source code of the original test class, we can use below code in our Junit test to inject mocked dependencies properly.
@InjectMocks private TestClass testClass; @Mock private Dependency1 dependency1; @Mock private Dependency2 dependency2; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); }
MockitoAnnotations.initMocks(this) basically initializes objects annotated with Mockito annotations for the test class. In our example, it is the testClass instance annotated with @InjectMocks. This line will search for any mocked dependencies for testClass instance & inject them properly. It can cover both Constructor injected & Field injected dependencies. So mixing of dependencies from the original test class is handled. In our case, both dependency1 & dependency2 objects should be properly injected now. NullPointerException should be resolved.