[英]JAVA mockito unit test for resttemplate and retryTemplate
我目前正在為以下方法編寫單元測試
@Autowired
private RequestConfig requestConfig;
@Autowired
private RetryTemplate retryTemplate;
public ResponseEntity<String> makeGetServiceCall(String serviceUrl) throws Exception {
try {
return retryTemplate.execute(retryContext -> {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = requestConfig.createHttpHeaders();
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
ResponseEntity<String> response = restTemplate.exchange(serviceUrl, HttpMethod.GET, entity, String.class);
return response;
});
} catch (Exception e) {
throw new Exception("Generic exception while makeGetServiceCall due to" + e + serviceUrl);
}
}
更新方法:
@Autowired
private RequestConfig requestConfig;
@Autowired
private RetryTemplate retryTemplate;
@Autowired
private RestTemplate restTemplate;
public ResponseEntity<String> makeGetServiceCall(String serviceUrl) throws Exception {
try {
return retryTemplate.execute(retryContext -> {
HttpHeaders headers = requestConfig.createHttpHeaders();
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
ResponseEntity<String> response = restTemplate.exchange(serviceUrl, HttpMethod.GET, entity, String.class);
return response;
});
} catch (Exception e) {
throw new Exception("Generic exception while makeGetServiceCall due to" + e + serviceUrl);
}
}
我嘗試了所有可能性,但我無法做對。 這是我的以下測試。
@Mock
private RestTemplate restTemplate;
@Mock
public RequestConfig requestConfig;
@InjectMocks
private RetryTemplate retryTemplate;
ServiceRequest serviceRequest;
@Test
public void makeGetServiceCall() throws Exception {
String url = "http://localhost:8080";
RetryTemplate mockRetryTemplate = Mockito.mock(RetryTemplate.class);
RestTemplate mockRestTemplate = Mockito.mock(RestTemplate.class);
ResponseEntity<String> myEntity = new ResponseEntity<>(HttpStatus.ACCEPTED);
Mockito.when(mockRetryTemplate.execute(ArgumentMatchers.any(RetryCallback.class), ArgumentMatchers.any(RecoveryCallback.class), ArgumentMatchers.any(RetryState.class))).thenReturn(myEntity);
Mockito.when(mockRestTemplate.exchange(
ArgumentMatchers.eq(url),
ArgumentMatchers.eq(HttpMethod.GET),
ArgumentMatchers.<HttpEntity<String>>any(),
ArgumentMatchers.<Class<String>>any())
).thenReturn(myEntity);
ResponseEntity<String> response = serviceRequest.makeGetServiceCall(url);
Assert.assertEquals(myEntity, response);
}
更新的測試用例:
@Mock
public RequestConfig requestConfig;
@Mock
private RestTemplate restTemplate;
@Mock
private RetryTemplate retryTemplate;
@InjectMocks
ServiceRequest serviceRequest;
@Test
public void makeGetServiceCall() throws Exception {
//given:
String url = "http://localhost:8080";
when(requestConfig.createHttpHeaders()).thenReturn(null);
ResponseEntity<String> myEntity = new ResponseEntity<>( HttpStatus.ACCEPTED);
when(retryTemplate.execute(any(RetryCallback.class), any(RecoveryCallback.class), any(RetryState.class))).thenAnswer(invocation -> {
RetryCallback retry = invocation.getArgument(0);
return retry.doWithRetry(/*here goes RetryContext but it's ignored in ServiceRequest*/null);
});
when(restTemplate.exchange(anyString(), any(HttpMethod.class), any(HttpEntity.class), eq(String.class)))
.thenReturn(myEntity);
//when:
ResponseEntity<String> response = serviceRequest.makeGetServiceCall(url);
//then:
assertEquals(myEntity, response);
}
我從我的方法調用makeGetServiceCall
得到的響應對象總是返回 null。 當我調試代碼時,我看到異常org.mockito.exceptions.misusing.WrongTypeOfReturnValue: ResponseEntity cannot be returned by toString() toString() should return String
error on the resttemplate
mocking where I return myEntity
我不確定我錯過了什么。
好吧,你犯了很多錯誤......
private RetryTemplate retryTemplate;
使用@Mock
,而不是@InjectMocks
@InjectMocks
應該進入ServiceRequest serviceRequest;
serviceRequest
無關的mockRetryTemplate
和mockRestTemplate
交互。 相反,您應該使用@Mock
注釋的字段來定義交互,因為它們被注入到您的測試對象中( serviceRequest
)RestTemplate
並將其注入到您的ServiceRequest
因為您首先RestTemplate
對ServiceRequest
RestTemplate
使用依賴注入。 您只需在ServiceRequest.makeGetServiceCall
實例化它的實例Mockito.when(retryTemplate.execute(...
. 您的交互指定RetryTemplate.execute(RetryCallback, RecoveryCallback, RetryState)
行上的錯誤方法上定義交互RetryTemplate.execute(RetryCallback, RecoveryCallback, RetryState)
而您的ServiceRequest
使用另一種方法RetryTemplate.execute(RetryCallback)
RetryTemplate.execute
是最終的,所以你不能像這里解釋的那樣不做額外的努力來模擬它。 而通常,你應該更喜歡在接口類,例如RestOperations
和RetryOperations
超過RestTemplate
和RetryTemplate
分別,更靈活。 也就是說,下面是解決您問題的工作測試。 但是要注意去掉RestTemplate restTemplate = new RestTemplate();
來自ServiceRequest
並使restTemplate
成為一個字段,因此它是依賴注入的。
@RunWith(MockitoJUnitRunner.class)
public class ServiceRequestTest {
@Mock
private RestTemplate restTemplate;
@Mock
public RequestConfig requestConfig;
@Mock
private RetryTemplate retryTemplate;
@InjectMocks
ServiceRequest serviceRequest;
@Test
public void makeGetServiceCall() throws Exception {
//given:
String url = "http://localhost:8080";
ResponseEntity<String> myEntity = new ResponseEntity<>(HttpStatus.ACCEPTED);
when(retryTemplate.execute(any(RetryCallback.class))).thenAnswer(invocation -> {
RetryCallback retry = invocation.getArgument(0);
return retry.doWithRetry(/*here goes RetryContext but it's ignored in ServiceRequest*/null);
});
when(restTemplate.exchange(eq(url), eq(HttpMethod.GET), any(HttpEntity.class), eq(String.class)))
.thenReturn(myEntity);
//when:
ResponseEntity<String> response = serviceRequest.makeGetServiceCall(url);
//then:
assertEquals(myEntity, response);
}
}
對我來說,下面的工作,否則,它總是返回 null
when(retryTemplate.execute(any(),any(),any())).thenAnswer(invocation -> {
RetryCallback retry = invocation.getArgument(0);
return retry.doWithRetry(null);
});
和 import 是import static org.mockito.ArgumentMatchers.any;
通用解決方案:
Mockito.when(retryTemplate.execute(Matchers.any(),Matchers.any(),Matchers.any())).thenAnswer(invocation -> {
RetryCallback retry = invocation.getArgumentAt(0,Matchers.any());
return retry.doWithRetry(null);
});
這個對我有用!
@ExtendWith(MockitoExtension.class)
class RetryableRestClientTest {
@Mock
private RestTemplate restTemplate;
@Mock
private RetryTemplate retryTemplate;
@InjectMocks
private RetryableRestClient client;
@SuppressWarnings("rawtypes")
@Test
void test_get() {
String url = "https://faked-url";
ResponseEntity<String> expectedResponseEntity = new ResponseEntity<>(HttpStatus.OK);
Mockito.when(retryTemplate.execute(Mockito.any(), Mockito.any(), Mockito.any()))
.thenAnswer(invocation -> {
RetryCallback retry = invocation.getArgument(0);
return retry.doWithRetry(null);
});
Mockito.when(restTemplate.exchange(Mockito.eq(url), Mockito.eq(HttpMethod.GET), Mockito.any(HttpEntity.class), Mockito.eq(String.class)))
.thenReturn(expectedResponseEntity);
ResponseEntity<String> actualResponseEntity = client.get(url);
Assertions.assertEquals(expectedResponseEntity, actualResponseEntity);
}
}
@Component
public class RetryableRestClient {
@Autowired
private RetryTemplate retryTemplate;
@Autowired
private RestTemplate restTemplate;
private HttpHeaders fakeHttpHeaders() {
HttpHeaders headers = new HttpHeaders();
// fake browser's behavior
headers.add("authority", "m.nowscore.com");
headers.add("cache-control", "max-age=0");
headers.add("sec-ch-ua", "\" Not;A Brand\";v=\"99\", \"Google Chrome\";v=\"91\", \"Chromium\";v=\"91\"");
headers.add("sec-ch-ua-mobile", "?0");
headers.add("upgrade-insecure-requests", "1");
headers.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36");
headers.add("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9");
headers.add("sec-fetch-site", "none");
headers.add("sec-fetch-mode", "navigate");
headers.add("sec-fetch-user", "?1");
headers.add("sec-fetch-dest", "document");
headers.add("accept-language", "en-US,en;q=0.9");
return headers;
}
public final ResponseEntity<String> get(String url) {
return retryTemplate.execute(context -> restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(null, fakeHttpHeaders()), String.class));
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.