代码之家  ›  专栏  ›  技术社区  ›  Kamil W

使用Spock模拟弹簧支撑模板

  •  2
  • Kamil W  · 技术社区  · 7 年前

    谁能给我举个例子,如何使用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的行为,我正在寻找解决方案,如何以正确的方式做到这一点。我不用弹簧靴。

    1 回复  |  直到 7 年前
        1
  •  4
  •   Ivan Lymar    7 年前

    情况如下:

    RestTemplate 在你的服务课上。

      private RestTemplate restTemplate = new RestTemplate();
    

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

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

    但您的服务中仍然包含常见的rest模板。您应该注入模拟对象。我建议你通过构造函数来做。因此,请将代码更改为:

    @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

    附笔

    spring认为构造函数注入是一种很好的做法。

    与在所有服务中创建新对象相比,最好创建RestTemplate bean并将其注入到任何地方。