unit-testinggroovyspock

How to mock with Spock


I want to mock with Spock a method getEntity for the Spring ResTemplate

Product getProducts(ProductSearch request) {
  Map<String, Object> queryParam = new HashMap<>();
  queryParam.put("id", request.getProductId());
  queryParam.put("category", request.getCategory());

  UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromHttpUrl(url);
  queryParam.forEach(uriComponentsBuilder::queryParam);

  String url = uriComponentsBuilder.toUriString();
  return restTemplate.getForEntity(url, Product.class).getBody();
}

The problem I face is how to I mock the getBody() part . I tried this and got a NullPointerException

class ProductClientSpec extends Specification {
  RestTemplate restTemplate = Mock()
  ProductClient legacyOpenSlotsClient = new ProductClient(restTemplate)

  def setup() {}

  def 'should return product'() {
    given:
    ProductSearch request = createProductRequest()
    Product product = createProductResponse()

    when:
    ProductClient.getProducts(request)

    then:
    1 * restTemplate.getForEntity("http://localhost:8080/products", Product.class).getBody() >> product
  }
}

Solution

  • Adding some line breaks to avoid having to scroll horizontally and to reveal the main problem:

    then:
      1 * restTemplate
        .getForEntity("http://localhost:8080/products", Product.class)
        .getBody()
      >> product
    

    Chained method calls are invalid syntax for mocking. The second method call is on the ResponseEntity returned by the first, but that one you did not mock.

    Lacking an MCVE to try this on, the next bit of code is just an untested sketch to show how this could be done in principle:

    RestTemplate restTemplate = Mock()
    ResponseEntity responseEntity = Mock()
    // ...
    
    then:
      1 * restTemplate.getForEntity("http://localhost:8080/products", Product.class) >> responseEntity 
      1 * responseEntity.getBody() >> product