【问题标题】:RestTemplate mocking gives NullPointerExceptionRestTemplate 模拟给出 NullPointerException
【发布时间】:2018-06-26 15:52:44
【问题描述】:

我的服务类代码如下:

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;
}
}

我的测试类如下:

@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");
}

}

在运行测试时,我在给出 Mockito.when 和 thenReturn 条件的那一行得到 NullPointerException。我尝试了很多组合,但它仍然给出 NPE。我什至无法到达方法调用。你能告诉我我哪里出错了吗?

【问题讨论】:

    标签: spring-boot mockito resttemplate


    【解决方案1】:

    你得到NullPointerException是因为你在Mockito.when中做的太多了。您在when 中的代码(较短的版本):

    restTemplate.exchange(args).getBody()

    您正在尝试模拟 getBody(),但它在 exchange(args) 上被调用。 exchange(args) 返回什么? Mockito 不知道它应该返回什么,您也没有指定,所以默认情况下它返回 null。

    这就是你获得 NPE 的原因。

    要解决此问题,您可以逐步进行模拟,即。

    ResponseEntity re = Mockito.when(exchange.getBody()).thenReturn(customerDataDto);
    Mockito.when(restTemplate.exchange()).thenReturn(re);
    

    或者指定mock返回deep stubs,像这样(如果你想使用注解的话):

    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
    RestTemplate restTemplate;
    

    【讨论】:

    • 我使用了您建议的注释,即 Answers.RETURNS_DEEP_STUBS 并且测试通过了。非常感谢。到现在为止,我对深层次的嘲笑一无所知。我现在知道了 。再次感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-30
    相关资源
    最近更新 更多