给定一个类 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
是一个类,而不是一个接口(interface),它实现了实际的 HTTP 传输。两者都阻碍了编写可测试的方法。最重要的是,您正在构造一个对操作系统级别有副作用的类的实例,而不是将其注入(inject),这一事实对这种情况没有帮助。那么解决的方法是:
- 基于接口(interface)而不是实现来编写方法,
RestOperations
在这种情况下 - 注入(inject)一个实现
RestOperations
的实例,例如RestTemplate
的一个实例对于生产,通过构造函数参数(首选)、方法参数或通过Supplier<RestOperations>
定义为类上的字段 - 用测试实现或测试中的模拟替换实际实例。我想选择
Mockito.mock(RestOperations.class)
更容易因为RestOperations
就像所有其他 Spring 接口(interface)定义了太多手动编写测试实现的方法
所以在 EncoderService
你可以拥有:
private final RestOperations restClient;
public EncoderService(RestOperations restClient) {
this.restClient = restClient;
}
public ResponseEntity<Object> createNewStream(Long channelId) {
...
ResponseEntity<Object> response = restClient.postForEntity(...
...
}
然后在 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
对于其他两种情况,测试设置完全相同,只是您将实例而不是构造函数传递到方法调用中,或者覆盖EncoderService
上的供应商。实例返回 testClient
.
我已经回答了一个关于 ProcessBuilder
的非常类似的问题它对操作系统级别也有副作用,并且是直接在此处测试的方法中构建的 Error trying to mock constructor for ProcessBuilder using PowerMockito您可以应用完全相同的策略。
关于java - 在单元测试中模拟 RestTemplate#postForObject,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50245444/