【问题标题】:How to mock resttemplate calls in spring boot?如何在 Spring Boot 中模拟 resttemplate 调用?
【发布时间】:2019-06-06 03:24:03
【问题描述】:

我尝试为调用第 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 在 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)

它正在调用测试类中的 api,我不希望发生这种情况。 我需要模拟 3rd 方 api 的 resttemplate 调用。我怎么能在不实际调用 api 的情况下做到这一点?

【问题讨论】:

  • 老实说,它不应该在没有明确配置的情况下调用任何东西,因为它是 MOCK,所以没有实现underneth并且会返回(就像你说你想要的那样)
  • 我建议wiremock.org

标签: maven unit-testing spring-boot resttemplate spring-test


【解决方案1】:

这就是问题

public class ForceService {
    private ForceServiceConfig config;
    private RestTemplate restTemplate = new RestTemplate(); // HERE

您正在创建新的 REAL rest 模板。你可能想要的是

  1. 使用您在包装测试类中创建的模拟
  2. 使用真正的休息模板并对其进行间谍活动。

不知道您的实际结构(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());

【讨论】:

  • 但是你没有使用 spring runner,所以 autowire 不起作用。但是,您可以在普通的 Mockito 中使用 @InjectMocks。我首选的方法是构造函数注入,所以我从来没有遇到过这样的困境,因为我可以提供我想要的任何东西,因为我将整个“环境”作为构造函数参数传递 - 不需要注入 DI 等。
猜你喜欢
  • 2020-05-01
  • 1970-01-01
  • 2019-12-26
  • 2017-07-13
  • 2019-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
相关资源
最近更新 更多