【问题标题】:Mockito mock restTemplate not using returning mock valueMockito 模拟 restTemplate 不使用返回模拟值
【发布时间】:2019-07-17 21:57:49
【问题描述】:

相关代码如下:

服务代码:

@Override
public ResponseEntity<AppointmentResponse> createAppointment(AppointmentRequest partnerFulfillmentRequest) {

    RestTemplate rt                                 = null;
    ResponseEntity<AppointmentResponse> response    = null;
    String uri                                      = null;
    HttpEntity<AppointmentRequest> httpEntity       = null;
    HttpHeaders headers = null;
    try {
            rt = new RestTemplate();
            rt.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
            rt.getMessageConverters().add(new StringHttpMessageConverter());
            uri = new String(internalServiceUrl+"/"+APP_NAME_INTERNAL+"/appointment");
            log.info("Calling internal service URL : "+uri);
            headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            httpEntity = new HttpEntity<AppointmentRequest>(partnerFulfillmentRequest, headers);  
            response =  rt.exchange(uri, HttpMethod.PUT, httpEntity, AppointmentResponse.class);
            if (response != null)
            {
                log.info("Got response from internal servicec-->statusCode: "+response.getStatusCodeValue());
                log.info("Got response from internal service--> Body "+response.getBody());
            }


    }catch(HttpClientErrorException hceEx) {
        //hceEx.printStackTrace();
        AppointmentResponse res = new AppointmentResponse();
        return new ResponseEntity<AppointmentResponse>(mapResponse(hceEx.getResponseBodyAsString()), hceEx.getResponseHeaders(), hceEx.getStatusCode());
    }catch(Exception e) {
        e.printStackTrace();
        AppointmentResponse res = new AppointmentResponse();
        ResponseEntity<AppointmentResponse> wfmErrResponse = new ResponseEntity<AppointmentResponse>(res, HttpStatus.INTERNAL_SERVER_ERROR);
        log.error("ERROR WHILE CALLING INTERNAL SERVICE");
        log.error(uri);
        log.error(e);
        return wfmErrResponse;
    }
    return response;

}

测试代码:

@RunWith(MockitoJUnitRunner.class)
public class PartnerFulfillmentServiceImplTest {

@Mock
RestTemplate restTemplate;

@Mock
HttpHeaders httpHeaders;

@Mock
ResponseEntity responseEntity;

@InjectMocks
PartnerFulfillmentServiceImpl partnerFulfillmentService;

@Test
public void createAppointmentTest() {

    Whitebox.setInternalState(partnerFulfillmentService, "internalServiceUrl", "http://localhost:8080");

    AppointmentRequest appointmentRequest = new AppointmentRequest();
    appointmentRequest.setPartnerName("CENTRICITY");
    appointmentRequest.setTicketNumber("123ABC");

    httpHeaders = new HttpHeaders();
    httpHeaders.set("Content-type", "application/json");

    responseEntity = new ResponseEntity<>(
            "some response body",
            HttpStatus.OK
    );

    when(restTemplate.exchange(Mockito.anyString(),
            Mockito.<HttpMethod> any(),
            Mockito.<HttpEntity<?>> any(),
            Mockito.<Class<Object>> any()))
            .thenReturn(responseEntity);

    ResponseEntity<AppointmentResponse> response = partnerFulfillmentService.createAppointment(appointmentRequest);

    Assert.assertEquals(response.getStatusCode(), HttpStatus.OK);
}
}

我得到 java.lang.AssertionError: 预计:500 实际:200 这是可以理解的,因为它实际上并没有调用运行.thenReturn(responseEntity); 逻辑。我的百万美元问题是,为什么?它应该返回 responseEntity 值。我有所有关于 exchange() 到 any() 的论据,希望尽可能频繁地触发条件,因为我总是可以在不同的时间缩小条件。我没有正确地嘲笑我的 restTemplate 吗?这是我目前对正在发生的事情的怀疑。任何建议都会有所帮助!

谢谢!

【问题讨论】:

  • 您的测试创建并存根模拟 restTemplate。但是你的方法没有使用那个模拟的 RestTemplate。它创建自己的新 RestTemplate 并使用它。

标签: java junit mockito resttemplate


【解决方案1】:

就像@JB Nizet 指出的那样,您正在测试方法中创建RestTemplate 的新实例。这意味着将从新实例调用exchange 方法,而不是模拟。如果包含 createAppointment 方法的类具有 RestTemplate 的依赖注入,则可以按照您的方式实现它。

你想要的是模拟 RestTemplate 的新实例的构造函数,以便在创建新实例时将其替换。不幸的是,Mockito 不能模拟构造函数,所以你应该使用PowerMockito 来模拟构造函数。

whenNew(RestTemplate.class).withNoArguments().thenReturn(restTemplate);

responseEntity = new ResponseEntity<>(
            "some response body",
            HttpStatus.OK
    );

when(restTemplate.exchange(Mockito.anyString(),
        Mockito.<HttpMethod> any(),
        Mockito.<HttpEntity<?>> any(),
        Mockito.<Class<Object>> any()))
        .thenReturn(responseEntity);

【讨论】:

  • 太棒了!我不在办公室,但明天早上我会先试试这个!谢谢加布里埃尔!
  • 或者 - 如果您不能或不想使用 PowerMockito - 您可以将 RestTemplte 的创建移至其他方法,并在使用 spy 时替换此功能。
  • 这是一个很好的建议@second。这一切都归结为决定将新实例封装在不同的方法上,以便您可以监视它,或者添加新的依赖项。
  • 不得不做一个小的重构来添加一个构造函数并注入restTemplate。像魅力一样工作!感谢@GabrielPimenta 和 JB Nizet!
猜你喜欢
  • 1970-01-01
  • 2022-01-24
  • 2022-01-11
  • 1970-01-01
  • 2021-01-07
  • 1970-01-01
  • 2014-04-01
  • 2019-01-06
  • 2020-01-21
相关资源
最近更新 更多