【问题标题】:Spring Rest Template mocking with Spock使用 Spock 模拟 Spring Rest 模板
【发布时间】:2017-11-14 14:33:12
【问题描述】:

谁能给我一个例子,如何使用 Spock 测试 RestTemplate。 我的课程如下所示:

@Service
public class SomeService {

    @Autowired
    private EndpointUrlProvider endpointUrlProvider;
    private RestTemplate restTemplate = new RestTemplate();

    public SomeResponse doSomePostRequest(HttpEntity<?> httpEntity) throws Exception {
    ResponseEntity<SomeResponse> response;
            try{
                response = restTemplate.postForEntity(endpointUrlProvider.getSomeUrl(),httpEntity,SomeResponse.class);
            } catch (Exception e){
                throw new Exception("Exception occured during post for:" + httpEntity.getBody().getClass().getSimpleName() + " Cause: " + e.getMessage());
            }
            if(response.getStatusCode() == HttpStatus.OK){
                return response.getBody();
            }
            throw new Exception("Error during " + response.getBody().getClass().getSimpleName() + "Http status is diffrent than 200: " + response.getBody().toString());
        }
    }

测试:

class SomeTest extends Specification {

    RestTemplate restTemplate = Mock {
        postForEntity(_, _, SomeResponse.class) >> new ResponseEntity(new SomeResponse(), HttpStatus.OK)
    }

    @Autowired
    SomeService someService

    def "someTest"() {
        when:
        SomeResponse someResponse = someService.doSomePostRequest(new HttpEntity<>(new SomeBody(), new HttpHeaders()))
        then:
        someResponse == new SomeResponse()
    }
}

主要问题是模拟 RestTemplate 的行为,我正在寻找解决方案如何以正确的方式做到这一点。我不使用弹簧靴。

【问题讨论】:

  • 什么不起作用?至于someResponse == new SomeResponse(),这只有在SomeResponse 覆盖equals 时才有效,否则肯定会失败。
  • 感谢您的建议,但是当我运行测试 postForEntity() 方法时,问题出在其他地方,而不是返回在模拟中声明的值

标签: java spring mocking spock resttemplate


【解决方案1】:

情况如下:

您在服务类中创建新的RestTemplate

  private RestTemplate restTemplate = new RestTemplate();

然后您在测试中创建模拟并调用您的服务方法:

    RestTemplate restTemplate = Mock {
            postForEntity(_, _, SomeResponse.class) >> new ResponseEntity(new SomeResponse(), HttpStatus.OK)
        }
                  ....
    someService.doSomePostRequest

但是您的服务内部仍然有通常的休息模板。您应该注入模拟对象。我建议你通过构造函数来做。所以把你的代码改成:

@Service
public class SomeService {

private EndpointUrlProvider endpointUrlProvider;
private RestTemplate restTemplate;

@Autowired
public SomeService(EndpointUrlProvider endpointUrlProvider, RestTemplate restTemplate){
  this.endpointUrlProvider = endpointUrlProvider;
  this.restTemplate = restTemplate;
}

你的测试将是:

class SomeTest extends Specification {

    RestTemplate restTemplate = Mock {
        postForEntity(_, _, SomeResponse.class) >> new ResponseEntity(new SomeResponse(), HttpStatus.OK)
    }

    SomeService someService = new SomeService (  null, restTemplate);

    def "someTest"() {
        when:
        SomeResponse someResponse = someService.doSomePostRequest(new HttpEntity<>(new SomeBody(), new HttpHeaders()))
        then:
        someResponse == new SomeResponse()
    }
}

现在您的服务对象将调用注入 MOCK 的方法,而不是通常的 RestTemplate

附言

构造函数注入被认为是春天的好习惯。

最好创建一个 RestTemplate bean 并将其注入各处,而不是在所有服务中创建新对象。

【讨论】:

  • 我不能在构造函数中注入带有@Autowired 注释的RestTemplate,因为它是非bean 类。还应注入 EndpointUrlProvider。 ;)
  • @KamilDS 让它成为一个 bean。只需将 RestTemplate bean 定义添加到您的 spring 上下文中。
  • 我看到这行得通。但是如何在一个构造函数中注入我的 endpointUrlProvider 和 RestTempate 模拟类?我在我的测试类中尝试了 autowired endpointUrlProvider 并将它传递给构造函数,但是当我触发我的测试时它为空。
  • @KamilDS 您可以创建弹簧测试上下文,在那里创建 urlProvider bean 并将其自动连接到您的测试。然后将其传递给构造函数。或者使 url 提供程序也被模拟
  • @KamilDS 看起来像另一个问题:D 你可以在 Spring 部分问它,例如“如何在测试中使用 spring bean”
猜你喜欢
  • 1970-01-01
  • 2020-04-23
  • 1970-01-01
  • 2015-08-03
  • 2022-06-11
  • 2013-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多