Reputation: 1004
My service class code is as below:
public class MyServiceImpl implements MegatillAccessService {
@Autowired
RestTemplate restTemplate;
@Value("${api.key}")
private String apiKey;
@Value("${customers.url}")
private String postUrl;
@Override
public String pushCustomerData(List<Customer> listOfcustomers, String storeId) throws MyServiceException {
Set<Customer> setOfCustomers = new HashSet<>(listOfcustomers);
int noOfCustomersLoadedSuccessfully =0;
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("apiKey", apiKey);
headers.add("Content-Type", "application/json");
headers.add("storeId", storeId);
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
for(Customer customer: setOfCustomers){
HttpEntity<Customer> request = new HttpEntity<Customer>(customer, headers);
CustomerDataDto customerDataDto = null;
try {
customerDataDto = restTemplate.exchange(postUrl, HttpMethod.POST, request, CustomerDataDto.class).getBody();
}
catch (HttpClientErrorException ex) {
if (ex.getStatusCode().equals(HttpStatus.NOT_FOUND)) {
log.error("The customers service is not available to load data: "+ ex.getResponseBodyAsString(), ex);
throw new MyServiceException("The customers service is not available to load data",new RuntimeException(ex));
}
else{
log.warn("Error for customer with alias: "+customer.getAlias() +" with message: "+ ex.getResponseBodyAsString(), ex);
if(!ex.getResponseBodyAsString().contains("already found for this shop")){
throw new MyServiceException("An error occurred while calling the customers service with status code "+ex.getStatusCode(),new RuntimeException(ex));
}
}
}
catch(Exception e){
throw new MyServiceException("An error occurred while calling the customers service: ",new RuntimeException(e));
}
if(null != customerDataDto) {
noOfCustomersLoadedSuccessfully++;
log.debug("--------Data posted successfully for: ---------"+customerDataDto.getAlias());
}
}
String messageToReturn = "No. of unique customers from source: "+setOfCustomers.size()+". No. of customers loaded to destination without error: "+noOfCustomersLoadedSuccessfully;
return messageToReturn;
}
}
My Test class is as below:
@RunWith(MockitoJUnitRunner.class)
@SpringBootTest
public class MyServiceTest {
@InjectMocks
private MyService myService = new MyServiceImpl();
@Mock
RestTemplate restTemplate;
@Before
public void setUp() throws Exception
{
MockitoAnnotations.initMocks(this);
initliaizeModel();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
}
@Test
public void pushAllRecords(){
Mockito.when(restTemplate.exchange(Matchers.anyString(), Matchers.any(HttpMethod.class), Matchers.<HttpEntity<?>> any(), Matchers.<Class<CustomerDataDto>> any()).getBody()).thenReturn(customerDataDto);
/*Mockito.when(restTemplate.exchange(Mockito.anyString(),
Mockito.<HttpMethod> eq(HttpMethod.POST),
Matchers.<HttpEntity<?>> any(),
Mockito.<Class<CustomerDataDto>> any()).getBody()).thenReturn(customerDataDto);*/
String resultReturned = myService.pushCustomerData(customers,"1235");
assertEquals(resultReturned, "No. of unique customers from source: 2. No. of customers loaded to destination without error: 2");
}
}
While running the test, I am getting NullPointerException at the line where I am giving the Mockito.when and thenReturn condition. I tried many combinations but it is still giving NPE. I can't even reach the method invocation.Can you please let me know where am I going wrong?
Upvotes: 4
Views: 8220
Reputation: 3494
You get NullPointerException
because you are doing too much in your Mockito.when
. Your code inside when
(shorter version):
restTemplate.exchange(args).getBody()
You are trying to mock getBody()
but it is called on exchange(args)
. And what does exchange(args)
returns? Mockito doesn't know what it should return and you didn't specify that so by default it returns null
.
That's why you get NPE.
To fix this you can either do mocking step by step, ie.
ResponseEntity re = Mockito.when(exchange.getBody()).thenReturn(customerDataDto);
Mockito.when(restTemplate.exchange()).thenReturn(re);
or specify mock to return deep stubs, like that (if you want to use annotations):
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
RestTemplate restTemplate;
Upvotes: 11