【问题标题】:How do I unit test a Spring RestTemplate that takes a ResponseExtractor and RequestCallback?如何对采用 ResponseExtractor 和 RequestCallback 的 Spring RestTemplate 进行单元测试?
【发布时间】:2020-04-15 23:06:07
【问题描述】:

我正在使用 Groovy 进行开发,并且正在尝试为 Spring 的 RestTemplate 的以下使用编写一个 Spock 单元测试...

包括我的请求回调和响应提取器,以及我的 RestTemplate bean 初始化类。我正在使用 ResponseExtractor 从GET myurl/ 流式传输响应并将其复制到文件中。 RequestCallback 只是在请求上设置一些标头。

class RestTemplateConfig() {
  @Bean(name = 'myRestTemplate')
  RestTemplate getMyRestTemplate() {
    RestTemplate restTemplate = new RestTemplateBuilder().build()
    return restTemplate
  }
}

class MyClass() {

  @Autowired
  @Qualifier('myRestTemplate')
  RestTemplate restTemplate

  File getFile() {

     ResponseExtractor<Void> responseExtractor = { ClientHttpResponse response ->
       // do something with the response
       // in this case, the response is an input stream so we copy the input stream to a file
       myFile = response.getBody() // roughly, in a psuedocode-ish way
       return null
     }

     RequestCallback requestCallback = { ClientHttpRequest request ->
       request.getHeaders().setAccept([MediaType.APPLICATION_JSON])
     }

     File myFile
     // get my file data
     restTemplate.execute('myurl/', HttpMethod.GET, requestCallback, responseExtractor)
     return myFile
  }
}

该特定 execute(...) 方法的 Spring 框架文档:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html#execute-java.net.URI-org.springframework.http.HttpMethod-org.springframework.web.client.RequestCallback-org.springframework.web.client.ResponseExtractor-

如何模拟这些闭包中发生的事情?具体来说,我有兴趣模拟我的响应提取器,因为我当前的测试总是将myFile 返回为空。

    when:
    // do stuff

    then:
    1 * restTemplate.execute('myurl/, HttpMethod.GET, _, _) // how can I mock out the expected response here?
    0 * _

    myFile != null // this fails because myFile is null

【问题讨论】:

  • 你能在骨架上多放些肉,最好把你的问题变成MCVE吗?例如,我看不到您的应用程序类中的restTemplaterequestCallbackresponseExtractor 来自哪里。如果后两者可以通过构造函数或setter注入,则可以注入模拟。如果它们是由某种工厂类创建的,则可以存根该类。如果在被测类本身中有工厂方法,您可以在类上使用间谍并存根工厂方法。所以你看,答案取决于具体情况。
  • @kriegaex 当然。感谢您发布该指南。目前,requestCallbackresponseExtractor 在调用 restTemplate 的方法中初始化。我更新了我的帖子。如果需要更多信息,请告诉我。

标签: spring spring-boot groovy resttemplate spock


【解决方案1】:

在您按照我的要求更新示例代码后,我现在可以看得更清楚了。您遇到了一个典型的(非)可测试性问题:您的方法getFile 不仅仅是获取文件。它将两个依赖项实例化为局部变量,使它们不可模拟,因此整个方法大多不可测试。

所以你想重构以获得更好的可测试性,以便能够使用我在第一条评论中提到的一种测试方法:

  • 如果requestCallbackresponseExtractor 可以通过构造函数或setter 注入,则可以注入模拟。
  • 如果它们是由某种工厂类创建的,您可以存根该类。
  • 如果在被测类中存在工厂方法,您可以对类使用 spy 并存根工厂方法。

有关可测试性以及测试如何推动应用程序设计的更一般性讨论,请参阅我的其他答案 here,“常规 cmets”和“更新”部分。

如果有任何不清楚的地方,请随时提出相关的(!)后续问题。

【讨论】:

    猜你喜欢
    • 2011-06-06
    • 2019-11-21
    • 2017-06-19
    • 1970-01-01
    • 2015-11-05
    • 2015-06-16
    • 2020-05-06
    • 1970-01-01
    • 2012-01-08
    相关资源
    最近更新 更多