簡體   English   中英

Mockito.When not working for custom RestTemplate

[英]Mockito.When not working for custom RestTemplate

我需要對以下服務進行測試。 當我嘗試為自定義 restTemplate 執行 Mockito.When 時,我收到錯誤“org.mockito.exceptions.misusing.MissingMethodInvocationException:when() 需要一個必須是“模擬方法調用”的參數。例如:when( mock.getArticles()).thenReturn(articles);"。

但是,當我不這樣做時 when(env.getProperty("test1")).thenReturn("test"); 我收到錯誤“對“/null/Test/null”的 POST 請求的 I/O 錯誤:null;”

如何為此類服務正確進行測試?

測試班

@InjectMocks
private AccountService _accountService;
@Mock
private RestTemplate _restTemplate;


@Test
public void shouldGetAccount_200()  {
//when(_accountService.getRestTemplate()).thenReturn(_restTemplate);

when(env.getProperty("test1")).thenReturn("test");
when(env.getProperty("test2")).thenReturn("2"); 
when(_restTemplate.exchange(eq(String.format("%s/Test/%s", env.getProperty("test1"), env.getProperty("test2")), _accId), eq(HttpMethod.GET), any(), eq(TestRequest.class)))
        .thenReturn(new ResponseEntity<>(_resp, HttpStatus.OK));
assertThat(_accountService.getAcc(_accId, "test", "test", "test")).isEqualTo(_resp);
}

服務

public IResponse getAcc(String accId, String sessionId, String apiKey, String userName) {
    RestTemplate restTemplate = getRestTemplate();
    HttpHeaders headers = new HttpHeaders();
    headers.set(HttpHeaders.COOKIE, sessionId);
    headers.add("X-Forwarded-For", getIPAddress());
    headers.add("Authorization", String.format("PS-Auth key=%s; runas=%s;", apiKey, userName));
    HttpEntity<Map<String, Object>> entity = new HttpEntity<>(null, headers);
    ResponseEntity<TestRequest> response;
    
    return restTemplate.exchange(String.format("%s/Test/%s", env.getProperty("test1"), env.getProperty("test2"))), accId),HttpMethod.GET, entity, TestRequest.class);
}

public RestTemplate getRestTemplate() {

    SystemDefaultRoutePlanner routePlanner = new SystemDefaultRoutePlanner(ProxySelector.getDefault());
    CloseableHttpClient httpClient = HttpClients.custom().setRoutePlanner(routePlanner)
            .setConnectionManager(poolingHttpClientConnectionManager).build();

    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();

    requestFactory.setHttpClient(httpClient);

    RestTemplate restTemplate = new RestTemplate(requestFactory);
    List<ClientHttpRequestInterceptor> interceptorList = restTemplate.getInterceptors();

    if (tracingClientHttpRequestInterceptor != null) {
        interceptorList.add(tracingClientHttpRequestInterceptor);
        interceptorList.add(traceLogClientHttpRequestInterceptor);
        restTemplate.setInterceptors(interceptorList);
    }
    return restTemplate;
}

使用 when() 將行為分配給 Mockito 為您創建的模擬。 然而,這個模擬永遠不會被使用,因為你的getAcc()方法調用了getRestTemplate ,它總是創建一個新的 RestTemplate 實例。

顯而易見的解決方案是在您的配置類中使用getRestTemplate方法並將其用作 bean 工廠,將 RestTemplate bean 自動裝配到您的AccountService中。 然后您的 @InjectMocks 注釋將按預期工作,您會看到被測服務確實使用了提供的模擬對象。

*請記住,在 Spring 中可以通過三種方式注入 bean - 使用字段注入、方法注入或構造函數。 這在網上查找並不難,所以我只想說大多數用例使用構造函數注入處理得最好:

@Autowired
public AccountService(RestTemplate restTemplate) {
    this.restTemplate = restTemplate;
}

其次,您沒有顯示這一點,但我很確定getAcc中的 env 變量是某種環境變量持有者,並且也沒有正確注入服務,因此它不會被嘲笑。 我通常建議堅持使用@ConfigurationProperties (您可以輕松地模擬它們),或者至少查看MockEnvironment。

順便說一句,我想不出為什么服務每次都需要一個新的 RestTemplate 實例,而創建 RestTemplate 肯定超出了AccountService的范圍,因此將其移至配置也可以改善代碼的結構。 作為獎勵,您可以在需要時在其他服務中重用相同的 RestTemplate bean。

最終,您可能希望添加一個抽象層,創建一個單獨的 bean 來負責構造 url 並將必要的標頭添加到 RestTemplate 請求,以便getAcc方法更具可讀性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM