Mockito throwing NPE in Spring test class #BeforeAll method - spring

I'm trying to mock a service using Mockito and setting up all the method invocations in a #BeforeAll method. The code is the following:
#SpringBootTest
#AutoConfigureMockMvc(addFilters = false)
public class VirtualMachineServiceIntegrationTests {
#MockBean
static VirtualMachineService virtualMachineService;
#Autowired
private MockMvc mockMvc;
#Autowired
private ObjectMapper objectMapper;
static String courseId;
static String studentId;
static Long teamId;
static Long vmId;
static SystemImage os;
static VirtualMachineDTO virtualMachineDTO;
static ConfigurationDTO configurationDTO;
#BeforeAll
static void beforeAll() {
studentId = "student";
courseId = "course";
teamId = 1L;
vmId = 1L;
os = SystemImage.WINDOWS_10;
virtualMachineDTO = VirtualMachineDTO.builder()
.id(1L)
.num_vcpu(2)
.disk_space(1000)
.ram(4)
.status(VirtualMachineStatus.OFF)
.build();
configurationDTO = ConfigurationDTO.builder()
.id(1L)
.min_vcpu(2)
.min_disk(1000)
.min_ram(4)
.max_vcpu(12)
.max_disk(2000)
.max_ram(16)
.max_on(4)
.tot(20)
.build();
Mockito.when(Mockito.any(VirtualMachineService.class).createVirtualMachine(Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt())).thenReturn(virtualMachineDTO);
}
}
The NPE is throwed by Mockito even without the thenReturn method. If I move this line
Mockito.when(Mockito.any(VirtualMachineService.class).createVirtualMachine(Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt())).thenReturn(virtualMachineDTO);
inside a #Test method then, after throwing a NPE, it will output this:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Misplaced or misused argument matcher detected here:
-> at it.polito.ai.backend.VirtualMachineServiceIntegrationTests.createVirtualMachine(VirtualMachineServiceIntegrationTests.java:87)
-> at it.polito.ai.backend.VirtualMachineServiceIntegrationTests.createVirtualMachine(VirtualMachineServiceIntegrationTests.java:87)
-> at it.polito.ai.backend.VirtualMachineServiceIntegrationTests.createVirtualMachine(VirtualMachineServiceIntegrationTests.java:87)
-> at it.polito.ai.backend.VirtualMachineServiceIntegrationTests.createVirtualMachine(VirtualMachineServiceIntegrationTests.java:87)
-> at it.polito.ai.backend.VirtualMachineServiceIntegrationTests.createVirtualMachine(VirtualMachineServiceIntegrationTests.java:87)
-> at it.polito.ai.backend.VirtualMachineServiceIntegrationTests.createVirtualMachine(VirtualMachineServiceIntegrationTests.java:87)
-> at it.polito.ai.backend.VirtualMachineServiceIntegrationTests.createVirtualMachine(VirtualMachineServiceIntegrationTests.java:87)
You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
when(mock.get(anyInt())).thenReturn(null);
doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
verify(mock).someMethod(contains("foo"))
This message may appear after an NullPointerException if the last matcher is returning an object
like any() but the stubbed method signature expect a primitive argument, in this case,
use primitive alternatives.
when(mock.get(any())); // bad use, will raise NPE
when(mock.get(anyInt())); // correct usage use
Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.
I'm new at Spring testing and Mockito so I cannot figure it out what I'm doing wrong. Any help appreciated, thanks.

There are multiple things a bit strange here. The main/misunderstanding problem is:
Mockito#when is used to tell a concrete mock what to do on specific method call.
So normally it goes something like this:
Mockito.when(mock.doSomeThings(anyString()).thenReturn("whatever");
Applying this pattern to your code, this should do the trick:
Mockito.when(virtualMachineService.createVirtualMachine(Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(), Mockito.any Int(), Mockito.anyInt(), Mockito.anyInt())).thenReturn(virtualMachineDTO);
Besides this, it looks strange to that you declared everything as static.
I would remove static from all class members and change #BeforeAll to #Before or #BeforeEach (depending on if you use JUnit 4 or 5).

Related

Can this method be tested using mockito?

I am not sure how to test the first method in the service layer with Mockito as it is using the helper method. Below is my failed attempt at a test: I get an InvalidUseOfMatchersException in the second when clause.
Thanks in advance!
#Mock
private EntityRepository EntityRepo;
#InjectMocks
private EntityService EntityService;
public List<DTO> getAllDTOs(){
//first method
return entityRepo.findAll()
.stream()
.map(this::convertEntityToDTO)
.collect(Collectors.toList());
}
//helper method
public DTO convertEntityToDTO(Entity entity) {
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration()
.setMatchingStrategy(MatchingStrategies.LOOSE);
DTO dto = new DTO();
dto = modelMapper.map(entity, DTO.class);
return dto;
}
#Test
public void EntityService_GetAll_ReturnsDTOList() {
when(entityRepo.findAll()).thenReturn(Mockito.anyList());
//the second when clause: when(entityService.convertEntityToDTO(Mockito.any(Entity.class)))
.thenReturn(Mockito.any(DTO.class));
List<DTO>DTOList = entityService.getAllDTOs();
Assertions.assertThat(DTOList).isNotNull();
Mockito#any* methods are actually defined in class ArgumentMatchers and can only be used to match the call arguments when setting up a mock or when verifying calls. All matcher methods return null (but have side-effects of modifying a matcher stack to be able to properly detect and match mocked calls).
For instance, you might do Mockito.when(svc.print(Mockito.anyString()).doNothing() when you don't care about the input or Mockito.verify(svc.print(Mockito.anyString()), Mockito.never()) when you want to verify that the method has never been called.
When setting up your mock, you have to provide a real value in your thenReturn call:
when(entityRepo.findAll()).thenReturn(Collections.emptyList());
when(entityService.convertEntityToDTO(Mockito.any(Entity.class)))
.thenReturn(new DTO());

Spring boot with Mockito mocking NamedParameterJdbcTemplate

Trying to unit test a method which is defined as :
public void myMethod(List<? extends MyModel> model){
int[] result = namedParameterJdbcTemplate.batchUpdate("update query", SqlParameterSourceUtils.createBatch(model));
}
In my test class i am defining test method as
class MyTestClass{
#Mock
NamedParameterJdbcTemplate namedParameterJdbcTemplate;
#InjectMocks
MyDao dao;
#Test
public void testMyMethod() {
final int[] rowsAffected = new int[]{1,2};
when(namedParameterJdbcTemplate.batchUpdate(any(), SqlParameterSourceUtils.createBatch(Arrays.asList(anySet())))).thenReturn(rowsAffected);
List<MyModel> myModels = new ArrayList<>();
MyModel mymodel = new MyModel();
mymodel.setSomeParam("");
myModels.add(mymodel);
dao.myMethod(myModels);
}
}
While running this test method , i am getting NullPointerException in called method(myMethod()). int[] result is coming as null. My understanding is it should get the result from the stub in the mock.
Please help me understand what am i doing wrong.
It seems that you're not using the correct import for any() because if it would be the correct ArgumentMatchers.any() from Mockito, Mockito would complain that you don't use an ArgumentMatcher for both parameters of .batchUpdate().
You can statically import it with import static org.mockito.ArgumentMatchers.*; or use ArgumentMatchers.any().
So as first step, try the following:
when(namedParameterJdbcTemplate.batchUpdate(ArgumentMatchers.any(), ArgumentMatchers.any())).thenReturn(rowsAffected);
or be less generic and match the return type of SqlParameterSourceUtils.createBatch() with:
// I don't know what SqlParameterSourceUtils.createBatch() returns, so you might have to adjust it
when(namedParameterJdbcTemplate.batchUpdate(ArgumentMatchers.any(), ArgumentMatchers.eq("SOME RETURN"))).thenReturn(rowsAffected);
It worked by adding the cast to the Argument matchers:
Updated Code :
when(namedParameterJdbcTemplate.batchUpdate(anyString(), (SqlParameterSource[]) any())).thenReturn(rowsAffected);

Getting org.mockito.exceptions.misusing.UnfinishedStubbingException:

//Test code
class Topic_Service_test
{
#Mock
private Topic_Repository topic_repository;
#InjectMocks
private Topic_Service topic_service = Mockito.spy(new Topic_Service());
#Test
void get_topic_test()
{
Topic_Table topic = new Topic_Table(2,"java");
Mockito.when(topic_repository.findById(Mockito.anyInt()))
.thenReturn(Optional.of(topic));
Mockito.doReturn(topic).when(topic_service.get_topic(2));//.thenReturn(topic);
Assertions.assertEquals(topic,topic_service.get_topic(2));
}
}
class Topic_Service
{
#Autowired
private Topic_Repository topic_repository;
public Topic_Table get_topic(int id)
{
System.out.println("get topic exec");
return topic_repository.findById(id).orElse(new Topic_Table());
}
}
According to me, topic_service.get_topic(2); in Topic_Service_test class should return the object according to Mockito.doReturn(topic).when(topic_service.get_topic(2)); but actually
it is showing some error, which I am not getting it.
ERROR SHOWING:-
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at
io.practice.practice_course_api.
Topic_Service_test.get_topic_test(Topic_Service_test.java:53)
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, which is not supported
3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if
completed
You're using the wrong syntax. It should be:
Mockito.doReturn(topic).when(topic_service).get_topic(2);
That is the syntax you want to use on spies to avoid side-effects (for example: if the method invocation would throw an exception).
#Mock
private Topic_Repository topic_repository;
#InjectMocks
private Topic_Service topic_service = Mockito.spy(new Topic_Service());
Also instead of using it like this, the cleaner way would be to use constructor injection. Consider adding a constructor that has a parameter Topic_Repository and then manually create the spy in your test.

Exception while getting values from Mocked object using Mockito

I am writing junit using mockito for a Spring #component class.
When it try to access the static field from final constant file throwing Null pointer exception.
CruserDomainTest
#RunWith(MockitoJUnitRunner.class)
public class CruserTest {
#InjectMocks
CruserDomain eDomain = new CruserDomain();
#Test
public void testGetCruseById() throws Exception,
{
String cCode = "AA";
int employeeId = 21305;
when(
cruseRepository.getTestId(
anyString(), anyInt())).thenReturn(
buildAndReturnList());
when(
payDomain.getRefPay(anyString(),
anyString(), anyString(), anyString()))
.thenReturn(buildPay());
CruseMember expectedResponse = eDomain.getMemberById(
airlineCode, employeeId);
}
CruserDomain
//getting null pointer exception in the below line execution
//while getting the current month
public CruseMember getMemberById(String cCode, int employeeId)
throws Exception {
//Some code //
if (contractMonth.getType().equals(
CruseConstant.CURRENT_MONTH)) {
currentMonthStartDate = cMonth.getStartDate();
} else if (contractMonth.getType().equals(
CruseConstant.OTHER_MONTH)) {
nextMonthStartDate = cMonth.getStartDate();
}
CruseConstant:
public final class CruseConstant {
public static final String CURRENT_MONTH = "C";
public static final String OTHER_MONTH = "O";
}
I tried with ReflectionTestutils but throwing exception while junit starts.
Help me on how to lookup final class static variables in the injectMocked class.
I strongly advise you to not mock domain objects, instead I would craft builders that can generate those objects.
Also in the code snippet #InjectMocks has no mock to inject, so injects nothing, mock fields should be declared in the test class. However I stress the point of not mocking the domain !
We've written this page on how to write good tests, I think TDD practitioners should read it, wether they use mockito or not. Lot of people contributed to refine this wiki page.
=> https://github.com/mockito/mockito/wiki/How-to-write-good-tests
It is really hard to understand your code because you have replaced the interesting parts with comments, but I would guess that you get a NPE because
contractMonth
is null. That is because you did not mock and/or forgot to define the behaviour of the class that you get the contractMonth from (CruserRepository?)

Why doesn't Mockito's when() get triggered?

I need to test a service class, but when I try to mock the dao class, it doesn't get triggered, thus not able to use ThenReturn().
I think that the problem is because I use an interface for my Dao and #Autowired in the service class (Spring MVC 3.1):
The interface:
public interface TestDao {
int createObject(Test test) throws NamingException;
}
The implementation:
#Repository
public class TestDaoImpl implements TestDao {
#Override
public int createObject(Test test) {
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(new InsertNewTest(test), keyHolder);
return ((java.math.BigDecimal)keyHolder.getKey()).intValue();
}
}
The service:
public class RegTest {
#Autowired
TestDao testDao;
public int regTest(int .....) {
.
.
int cabotageId = testDao.createObject(test);
}
}
In the test I have:
#RunWith(MockitoJUnitRunner.class)
public class TestRegService {
#InjectMocks
private RegTest regTest = new RegTest();
#Mock
TestDao testDao;
#Test()
public void test() {
.
when(testDao.createObject(null)).thenReturn(100);
.
}
testDao.createObject(null) returns 0 (due to being mock'ed) and not 100 as I is trying to achieve.
Can anybody help, please?
Problem solved!
It was the passing test-object to createObject() that did not match. Using
testDao.createObject(any(Test.class))
did the trick!
If your test is actually passing a value to createObject, then when(testDao.createObject(null)... never gets matched. Rather than matching on null, you could match any instance of Test with testDao.createObject(any(Test.class))...
Also when you tried later to supply new Test() as the argument to match, it will literally try to match on that exact instance of Test, but presumably your real code is new-ing up a different one. So the use of Matchers.any(Test.class) as the parameter to match is the way to go.
Mockito injection mechanism don't know about Spring #Autowired or CDI #Inject annotations. It just tries to find the best candidate given the type and the name of the mock, and it can lookup private fields too. See the javadoc of #InjectMocks : http://docs.mockito.googlecode.com/hg/1.9.0/org/mockito/InjectMocks.html
The semantic you are using is correct, though if you are experiencing issues, I would rather look for incorrect interactions or incorrect arguments.
Are you sure the test variable in regTest.regTest(int...) is really null when passed to testDao.createObject(test) ?
I don't know if this is a typo in the example, but you have RegTest.regTest() calling createTest() rather than createObject(). Otherwise, I don't think #Autowired has anything to do with it, since your test itself is not running in a container with Spring management. If it is not a typo, and createTest is in fact a real and different method from createObject, then the default behaviour of a mocked object in Mockito is to return the appropriately-typed zero for numeric return types.
I think that you're right about the autowire not getting called. You could inject the dao yourself using the setTestDao() call instead. Mockito also supports spy which allows you to trace the objects code and just replace functions instead.

Resources