如何在 spring 启动时模拟 resttemplate 调用?
How to mock resttemplate calls in spring boot?
我尝试为调用第 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 未找到
在 org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:78)
在 org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700)
在 org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:653)
它在测试 class 中调用 api,我不想发生这种情况。
我需要模拟第三方 api 的 resttemplate 调用。如果不实际调用 api 怎么办?
这就是问题所在
public class ForceService {
private ForceServiceConfig config;
private RestTemplate restTemplate = new RestTemplate(); // HERE
您正在创建新的 REAL 休息模板。你可能想要的是
- 使用您在包装测试中创建的模拟 class
- 使用真正的 rest 模板并对其进行监视。
不知道您的实际结构(1 个文件 2 classes),但可以安全地假设它不是,并且在任何情况下您都可以简单地将 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 只是一个几乎什么都不做的存根,并且如果没有其他指示,则在任何调用中 return 为 null - 将其保留为 @Mock
.
但是,如果你想让它正常工作并且只拦截一些特定的方法调用和存根响应,请使用 spy。
@Mock
private RestTemplate restTemplate;
private RestTemplate restTemplate=Mockito.mock(RestTemplate.class)
或
private RestTemplate restTemplate=Mockito.spy(new 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 未找到 在 org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:78) 在 org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700) 在 org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:653)
它在测试 class 中调用 api,我不想发生这种情况。 我需要模拟第三方 api 的 resttemplate 调用。如果不实际调用 api 怎么办?
这就是问题所在
public class ForceService {
private ForceServiceConfig config;
private RestTemplate restTemplate = new RestTemplate(); // HERE
您正在创建新的 REAL 休息模板。你可能想要的是
- 使用您在包装测试中创建的模拟 class
- 使用真正的 rest 模板并对其进行监视。
不知道您的实际结构(1 个文件 2 classes),但可以安全地假设它不是,并且在任何情况下您都可以简单地将 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 只是一个几乎什么都不做的存根,并且如果没有其他指示,则在任何调用中 return 为 null - 将其保留为 @Mock
.
但是,如果你想让它正常工作并且只拦截一些特定的方法调用和存根响应,请使用 spy。
@Mock
private RestTemplate restTemplate;
private RestTemplate restTemplate=Mockito.mock(RestTemplate.class)
或
private RestTemplate restTemplate=Mockito.spy(new RestTemplate());