用Spock模拟的弹簧架模板

2022-08-21 00:00:00 mocking spring java resttemplate spock

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


解决方案

情况如下:

您在服务类中创建了新的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()
    }
}

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

附注

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

最好是创建RestTemplate Bean并将其注入到任何地方,而不是在所有服务中创建新对象。

相关文章