maven - 如何在 Spring Boot 中模拟 resttemplate 调用?
问题描述
我尝试为调用第 3 方 api 的服务中的其余调用编写测试用例。
@RunWith(MockitoJUnitRunner.class)
public class ForceServiceTest {
private ForceService forceService;
@Mock
private ForceServiceConfig config;
@Mock
private RestTemplate restTemplate;
@Before
public void setup() {
forceService = new ForceService(config);
}
@Test
public void apiCall_valid() throws JSONException {
HttpHeaders headers = new HttpHeaders();
headers.set(CONTENT_TYPE, "application/x-www-form-urlencoded");
headers.set(ACCEPT, APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(
"id=null",
headers);
config.authTokenUrl = "https://ex...com/..";
Mockito.when(restTemplate.exchange(config.authTokenUrl, HttpMethod.POST, entity, Access.class)).thenReturn(null);
// Mockito.when(any()).thenReturn(null);
forceService.apiCall();
}
}
@Component
public class ForceService {
private ForceServiceConfig config;
private RestTemplate restTemplate = new RestTemplate();
public ForceService(ForceServiceConfig config) {
this.config = config;
}
private String apiCall() {
HttpHeaders headers = new HttpHeaders();
headers.set(CONTENT_TYPE, "application/x-www-form-urlencoded");
headers.set(ACCEPT, APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(
"&id=" + config.id,
headers);
ResponseEntity<Access> response = restTemplate.exchange(config.authTokenUrl, HttpMethod.POST, entity,
Access.class);
return response.getBody().token_type + " " + response.getBody().access_token;
}
}
我收到以下错误:
org.springframework.web.client.HttpClientErrorException: 404 Not Found at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:78) at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700 ) 在 org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:653)
它在测试类中调用 api,我不想发生这种情况。我需要模拟 3rd 方 api 的 resttemplate 调用。我怎么能在不实际调用 api 的情况下做到这一点?
解决方案
这就是问题
public class ForceService {
private ForceServiceConfig config;
private RestTemplate restTemplate = new RestTemplate(); // HERE
您正在创建新的 REAL rest 模板。你可能想要的是
- 使用您在包装测试类中创建的模拟
- 使用真正的休息模板和间谍就可以了。
不知道的是您的实际结构(1 个文件 2 个类),但可以安全地假设它不是,并且在任何情况下您都可以简单地将 RestTemplate 作为 ctor 参数传递。所以
@Component
public class ForceService {
private ForceServiceConfig config;
private RestTemplate restTemplate;
public ForceService(ForceServiceConfig config,RestTemplate restTemplate) {
this.restTemplate=restTemplate;
this.config = config;
}
和
@Before
public void setup() {
forceService = new ForceService(config,restTemplate);
}
现在,如果您希望 RestTemplate 只是一个不做任何事情的存根,并且如果没有另行指示,则在任何调用上都返回 null - 将其保留为@Mock
.
但是,如果您想让它正常工作并且只拦截一些特定的方法调用和存根响应,请使用 spy.
@Mock
private RestTemplate restTemplate;
private RestTemplate restTemplate=Mockito.mock(RestTemplate.class)
或者
private RestTemplate restTemplate=Mockito.spy(new RestTemplate());
推荐阅读
- r - 如何使用 R flexdashboard 向现有 HTML 文档添加新页面
- r - 零调整伽马模型的连续和二项式部分的组合效应的 P 值
- .net - .net 创建 HttpClient 以访问 Intuit Quickbooks
- python - 尝试将数组存储到数据框单元格时出错
- ios - 为什么 SwiftUI @State 对于简单状态更改的执行与 @ObservedObject 不同?
- angular - Angular Ionic 数据绑定
- assembly - 为什么 "add #0x10, sp" 给 sp 增加 16 位,而 "add #0x8, sp" 只增加 8 位?(微腐败 CTF,“库斯科”阶段)
- flutter - Flutter 中从 AppLocalizations.of(context) 动态获取字符串
- javascript - Ref 的 TypeScript 类型作为 React 中的参数
- javascript - 如何在订阅功能上捕获错误?