T Anna
T Anna

Reputation: 1004

RestTemplate mocking gives NullPointerException

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

Answers (1)

michalbrz
michalbrz

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

Related Questions