![](/img/trans.png)
[英]Mockito.mock is not working, using Mockito.when causes NullPointerException
[英]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.