Reputation: 2290
I'm doing InjectMocks and I'm getting this error: "java.lang.NullPointerException: ... is marked non-null but is null" which is due to a Non-Null check that I have. What I want to do is form an InjectMock, but this injectmock is object is constructed using parameters.
Here's some pseudocode:
@ExtendWith(MockitoExtension.class)
public class Tester {
@Spy private ClassA clA;
@InjectMocks
private ClassB clB = new clB(clA);
@BeforeEach
void setup() throws Exception {
Mock.when(clA.mymethod(Mockito.any())).thenReturn(Non_Null_Stuff);
}
}
I'm sure you can see what I'm trying to do here: create class B using a mocked version of class A, but it doesn't work because it gives me "clA is marked non-null but is null" at the @InjectMocks line. This is because the code for the construction of clB requires a non-null clA.
It seems that I am unable to place the InjectMocks line within the setup function and I cannot place the Mock.when before the InjectMocks, so I'm stuck. Any advice is greatly appreciated
Upvotes: 0
Views: 4393
Reputation: 61
Couple of issues here. The answer depends on what do you want to achieve.
To use Mockito annotations you should add next line above your class (in case if you use jUnit 5):
@ExtendWith(MockitoExtension.class)
And, this dependency to your pom (if you use Maven (you can find analog for Gradle here: https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter/3.3.3))
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>3.3.3</version>
<scope>test</scope>
</dependency>
@Spy
means that you will be using real object (not a mock) and it is mostly used to be able to make verifications on that object (check if certain methods was called appropriate number of times with appropriate arguments, see: https://www.baeldung.com/mockito-verify).
@Mock
means that you will be using mocked object and you should set it's beheviour using Mockito.when()
@Mock is used to exclude logic from being tested and make methods of objects behave in the way you need for particular unit test.
Hope this snippet of code will help you to understand the difference:
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ExtendWith(MockitoExtension.class)
public class Test {
@Spy
private ClassA classA; // it will be real object
@Mock
private ClassB classB; // it will be mock
@InjectMocks
private ClassC classC;
@org.junit.jupiter.api.Test
public void test() {
// for mock we should define it's behaviour for the test (here or in @BeforeEach annotated method)
Mockito.when(classB.mockedMethod()).thenReturn("Some overridden behaviour");
String result = classC.someMethod();
assertEquals("ClassA - Some overridden behaviour", result);
// verity that method on real object wall called
Mockito.verify(classA, Mockito.only()).realMethod();
// verity that method on mocked object wall called
Mockito.verify(classB, Mockito.only()).mockedMethod();
}
}
ClassA:
public class ClassA {
public String realMethod() {
return "ClassA";
}
}
ClassB:
public class ClassB {
public String mockedMethod(){
return "ClassB"; // we will not be using it's real behaviour
}
}
ClassC:
public class ClassC {
private ClassA classA;
private ClassB classB;
public ClassC(ClassA classA, ClassB classB) {
this.classA = classA;
this.classB = classB;
}
public String someMethod() {
return classA.realMethod() + " - " +classB.mockedMethod();
}
}
Upvotes: 1