[英]Mocking RestTemplate#postForObject in a unit test
Given a class EncoderService
which has the following createNewStream
method and a bunch of constants used in the method, how can I use mockito
to write a unit-test for the createNewStream
method: 给定一个
EncoderService
类,它具有以下createNewStream
方法和该方法中使用的一堆常量,如何使用mockito
为createNewStream
方法编写单元测试:
public ResponseEntity<Object> createNewStream(Long channelId) {
String url = IP + VERSION + serverName + VHOSTS + vhostName + APP_NAME + appName + STREAM_FILES;
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON_UTF8));
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
headers.setAcceptCharset(Arrays.asList(Charset.forName(UTF_8)));
RestTemplate restTemplate = new RestTemplate();
String udp = "udp://" + "localhost" + ":" + "1935";
Map<String, String> map = new HashMap<>();
map.put("name", STREAMS + appName + channelId);
map.put("serverName", serverName);
map.put("uri", udp);
HttpEntity<Map<String, String>> request = new HttpEntity<>(map, headers);
HttpStatus statusCode = null;
try {
ResponseEntity<Object> response = restTemplate.postForEntity(url, request, Object.class);
statusCode = response.getStatusCode();
map.put(MESSAGE, "successful");
return new ResponseEntity<>(map, statusCode);
} catch (HttpStatusCodeException e) {
map.put(MESSAGE, e.getMessage());
return new ResponseEntity<>(map, HttpStatus.BAD_REQUEST);
}
}
RestTemplate
is a class, not an interface, and it implements the actual HTTP transport. RestTemplate
是一个类,而不是一个接口,它实现了实际的HTTP传输。 Both are standing in the way of writing a testable method. 两者都妨碍编写可测试的方法。 On top of that the fact that you are constructing an instance of a class that has side effects on the OS level rather than getting it injected does not help the case.
最重要的是,您正在构造对OS级别具有副作用而不是注入它的类的实例并不能解决问题。 So the way to solve it is:
因此,解决方法是:
RestOperations
in this case RestOperations
RestOperations
, eg an instance of RestTemplate
for production, via a constructor argument (preferred), method argument or via a Supplier<RestOperations>
defined as a field on the class Supplier<RestOperations>
注入实现RestOperations
的实例,例如用于生产的RestTemplate
实例 Mockito.mock(RestOperations.class)
because RestOperations
just like all other Spring interfaces defines way too many method for writing a test implementation manually Mockito.mock(RestOperations.class)
比较容易,因为像所有其他Spring接口一样, RestOperations
定义了太多方法来手动编写测试实现 So in EncoderService
you can have: 因此,在
EncoderService
您可以拥有:
private final RestOperations restClient;
public EncoderService(RestOperations restClient) {
this.restClient = restClient;
}
public ResponseEntity<Object> createNewStream(Long channelId) {
...
ResponseEntity<Object> response = restClient.postForEntity(...
...
}
And then in EncoderServiceTest
: 然后在
EncoderServiceTest
:
ResponseEntity<Object> expectedReturnValue = ...
RestOperations testClient = mock(RestOperations.class);
doReturn(expectedReturnValue).when(testClient).postForEntity(any(), any(), anyClass());
EncoderService service = new EncoderService(testClient);
// use the service
For the other two cases the test setup is exactly the same, just you would pass the instance into the method call instead of constructor or overwrite the supplier on the EncoderService
instance to return the testClient
. 对于其他两种情况,测试设置是完全相同的,只是您将实例传递给方法调用而不是构造函数,或覆盖
EncoderService
实例上的供应商以返回testClient
。
I have answered a very similar question about ProcessBuilder
which also has side effects on the OS level and was constructed directly in the method under test here Error trying to mock constructor for ProcessBuilder using PowerMockito You can apply exactly the same tactics. 我已经回答了一个关于
ProcessBuilder
的非常相似的问题,该问题在操作系统级别上也有副作用,并且是直接在此处测试的方法中构造的。尝试使用PowerMockito模拟ProcessBuilder的构造函数时出错您可以应用完全相同的策略。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.