[英]JAVA mockito unit test for resttemplate and retryTemplate
I am currently writing unit test for below method我目前正在为以下方法编写单元测试
@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);
}
}
UPDATED METHOD:更新方法:
@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);
}
}
I tried all possibilities but I am unable to get it right.我尝试了所有可能性,但我无法做对。 Here is my below test.
这是我的以下测试。
@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);
}
UPDATED TEST CASE:更新的测试用例:
@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);
}
The response object which I get from my method call makeGetServiceCall
always return null.我从我的方法调用
makeGetServiceCall
得到的响应对象总是返回 null。 When I debug the code I see exception org.mockito.exceptions.misusing.WrongTypeOfReturnValue: ResponseEntity cannot be returned by toString() toString() should return String
error on the resttemplate
mocking where I return myEntity
当我调试代码时,我看到异常
org.mockito.exceptions.misusing.WrongTypeOfReturnValue: ResponseEntity cannot be returned by toString() toString() should return String
error on the resttemplate
mocking where I return myEntity
I am not sure what am I missing.我不确定我错过了什么。
Well, you have made quite some number of mistakes...好吧,你犯了很多错误......
private RetryTemplate retryTemplate;
private RetryTemplate retryTemplate;
with @Mock
, not @InjectMocks
@Mock
,而不是@InjectMocks
@InjectMocks
should go onto ServiceRequest serviceRequest;
@InjectMocks
应该进入ServiceRequest serviceRequest;
mockRetryTemplate
and mockRestTemplate
which have nothing to do with serviceRequest
.serviceRequest
无关的mockRetryTemplate
和mockRestTemplate
交互。 Instead, you should use your @Mock
-annotated fields to define interactions on because they are being injected into your object under test ( serviceRequest
)@Mock
注释的字段来定义交互,因为它们被注入到您的测试对象中( serviceRequest
)RestTemplate
and inject it into your ServiceRequest
because you don't use dependency injection in the first place for RestTemplate
in ServiceRequest
.RestTemplate
并将其注入到您的ServiceRequest
因为您首先RestTemplate
对ServiceRequest
RestTemplate
使用依赖注入。 You just instantiate its instance in ServiceRequest.makeGetServiceCall
ServiceRequest.makeGetServiceCall
实例化它的实例Mockito.when(retryTemplate.execute(...
. Your interaction specifies RetryTemplate.execute(RetryCallback, RecoveryCallback, RetryState)
whereas your ServiceRequest
uses another method RetryTemplate.execute(RetryCallback)
Mockito.when(retryTemplate.execute(...
. 您的交互指定RetryTemplate.execute(RetryCallback, RecoveryCallback, RetryState)
行上的错误方法上定义交互RetryTemplate.execute(RetryCallback, RecoveryCallback, RetryState)
而您的ServiceRequest
使用另一种方法RetryTemplate.execute(RetryCallback)
RetryTemplate.execute
is final and so you can't mock it without extra efforts as explained here .RetryTemplate.execute
是最终的,所以你不能像这里解释的那样不做额外的努力来模拟它。 And generally, you should prefer interfaces over classes, eg RestOperations
and RetryOperations
over RestTemplate
and RetryTemplate
respectively, to be more flexible.RestOperations
和RetryOperations
超过RestTemplate
和RetryTemplate
分别,更灵活。 That said, below is the working test which solves your problem.也就是说,下面是解决您问题的工作测试。 But take note of removing
RestTemplate restTemplate = new RestTemplate();
但是要注意去掉
RestTemplate restTemplate = new RestTemplate();
from ServiceRequest
and making restTemplate
a field so it's dependency-injected.来自
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);
}
}
For me below worked, otherwise, it was returning null always对我来说,下面的工作,否则,它总是返回 null
when(retryTemplate.execute(any(),any(),any())).thenAnswer(invocation -> {
RetryCallback retry = invocation.getArgument(0);
return retry.doWithRetry(null);
});
and import was import static org.mockito.ArgumentMatchers.any;
和 import 是
import static org.mockito.ArgumentMatchers.any;
Generic solution:通用解决方案:
Mockito.when(retryTemplate.execute(Matchers.any(),Matchers.any(),Matchers.any())).thenAnswer(invocation -> {
RetryCallback retry = invocation.getArgumentAt(0,Matchers.any());
return retry.doWithRetry(null);
});
It works for me!这个对我有用!
@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.