Spring 使用 Spock 模拟 Rest 模板

Spring Rest Template mocking with 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 的模拟行为,我正在寻找如何以正确的方式做到这一点的解决方案。我不使用 spring 引导。

情况如下:

您在服务 class 中创建了新的 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

p.s.

spring.

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

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