Search code examples
javaspring-bootspock

Spock Mock doesnt work inside lambda function


I can't find something about it, but it seems like the Spock mock doesn't work inside my lambda function. I have tried:

    RestTemplateAdapter restTemplateAdapter = Mock(RestTemplateAdapter)
    int maxRety = 5
    String baseUrl = "baseUrl"
    ProductRequestPort productRequestPort = new ProductRequestAdapter( restTemplateAdapter, baseUrl, maxRety)

        def "should throw erro"() {
        given:
        String errorMsg = "Error test message"
        Long customerCode = 1234L

        when:
        productRequestPort.find(customerCode)
        then:

        maxRety * restTemplateAdapter.exchange(_, _, _, _) >> { throw new RuntimeException(errorMsg) }
        GatewayException error = thrown(GatewayException.class)
        error.getMessage() == "Error when trying to get products."

    }

The method im trying to mock:

    public CompletableFuture<ProductListResponse> find(Long customerCode) {
    String url = BASE_URL + customerCode;
    HttpEntity<?> entity = new HttpEntity<>();

    return CompletableFuture.supplyAsync(() -> {
        return retrieveProductListResponse(customerCode, url, entity);
    });
}

    private ProductListResponse retrieveProductListResponse(Long customerCode, String url, HttpEntity<?> entity) {
    int attempt = 0;
    while (attempt < MAX_RETRIES) {
        try {
            ResponseEntity<ProductListResponse> response = restTemplateAdapter.exchange(
                    url,
                    HttpMethod.GET,
                    entity,
                    ProductListResponse.class
            );
            return response.getBody();
        } catch (Exception e) {
            attempt++;
        }
    }
    throw new GatewayException(ERROR_GETTING_PRODUCTS);}

I recive from the test execution:

    Too few invocations for:

maxRety * restTemplateAdapter.exchange(_, _, _, _) >> { throw new RuntimeException(errorMsg) }   (1 invocation)

And the Mock just return a "null" as response from restTemplateAdapter.

I placed my RestTemplate class inside an adapter because I thought Spock couldn't mock it properly, but even with the interface the error persist. If I open the method retrieveProductListResponse to public and call it from the test spock is capable of mock it. Due to this, I suspect that the issue might be related to the lambda inside CompletableFuture.


Solution

  • Your problem is not related to any nesting.

    You call productRequestPort.find which immediately returns a CompletableFuture and does the work asynchronously.

    Then you immediately check the outcome, which of course fails, as you did not wait for the work to complete.

    Wait for the CompletableFuture to complete before checking the expectations.