Reputation: 533
I have a simple test case for which I am using Mockito in spring boot application.
userOperation.java
...
@Autowired
Validator nameValidator;
private boolean userOperation(String name) {
NameStats nameStats = nameValidator.validate(name);
if (!nameStats.isSuccess()) {
throw new Exception();
}
return true;
}
...
Validator.java
public NameStats validate(String name)
{
NameStats nameStats = new NameStats();
// code goes here
return nameStats;
}
testCase.java
...
@SpringBootTest
@RunWith(SpringRunner.class)
public class ImportFileOperationTest {
@Mock
Validator nameValidator;
@Mock
NameStats nameStats;
@InjectMocks
UserOperation operation;
@Test
public void ConnectorDelegate0Test() {
Mockito.when(nameValidator.validate(any(String.class))).thenReturn(nameStats);
Mockito.when(nameStats.isSuccess()).thenReturn(true);
operation.userOperation(restConsumerRequest);
}
}
...
Error :
For the above test case, I am getting NullPointerException. While tracing I found out that below line of code in test returns the null value.
Mockito.when(nameValidator.validate(any(String.class))).thenReturn(nameStats);
Because of the null value, when it tries to call nameStats.isSuccess()
it is throwing nullpointexception even I have mocked the response to this function as true
.
Question : 1. Am I mocking the response right way? 2. Why the mocking function returns the null object?
Update :
testCase.java
@SpringBootTest
@RunWith(SpringRunner.class)
public class ImportFileOperationTest {
@MockBean
Validator nameValidator;
NameStats nameStats;
@InjectMocks
@Resource
UserOperation operation;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
@Test
public void ConnectorDelegate0Test() {
nameStats = new nameStats();
Mockito.when(nameValidator.validate(any(String.class))).thenReturn(nameStats);
Mockito.when(nameStats.isSuccess()).thenReturn(true);
operation.userOperation(restConsumerRequest);
}
}
I tried to create the object nameStats
manually and expected validate
function to return that object but still, it returns null
.
Any help would be appreciated.
Upvotes: 6
Views: 15793
Reputation: 886
Had a similar problem after upgrade to Spring Boot 2. The reason is explained here https://javadoc.io/static/org.mockito/mockito-core/3.3.3/org/mockito/ArgumentMatchers.html#any-java.lang.Class-
Since Mockito 2.1.0, only allow non-null instance of , thus null is not anymore a valid value.
So mock returns null, or empty list, because calls were set with anyString()
, and object passed was null. To match value or null, use matcher any()
.
Upvotes: 2
Reputation: 2423
The test shall be either Mockito-driven or Spring-driven. Spring-driven would have @SpringBootTest
and @RunWith(SpringRunner.class)
class-level annotations and mocks would be declared with @MockBean
or explicitly instantied with Mockito.initMocks
. Mockito-driven test would have @RunWith(MockitoJUnitRunner.class)
and mocks would be declared with @Mock
and/or injected with @InjectMocks
. Note the injection does not help when the instance such as NameStats
is instantied with new
in within the method.
The shown test does not have to be @SpringBootTest
and therefore it could be written as Mockito-driven test like this:
@RunWith(MockitoJUnitRunner.class)
public class ImportFileOperationTest {
@Mock
Validator nameValidator;
@InjectMocks
UserOperation operation;
@Test
public void connectorDelegateTest() {
NameStats nameStats = new NameStats();
nameStats.setStats(Stats.SUCCESS);
Mockito.when(nameValidator.validate(any(String.class))).thenReturn(nameStats);
operation.userOperation(restConsumerRequest);
}
Upvotes: 11
Reputation: 3170
You need to use @InjectMocks
for all class types and @Mock
need to be used for all associated attributes inside that class.
Example :
class Product {
ProductDetails productDetails;
}
class ProductDetails {
}
Sample Test case for above class :
@SpringBootTest
@RunWith(SpringRunner.class)
public class ProductTest {
@Mock
ProductDetails productDetails;
@InjectMocks
Product product;
}
Upvotes: 3