Search code examples
unit-testinggroovyspock

Use PollingConditions with return value in Spock?


I would like to use PollingConditions.eventually to evaluate and return value:

    @Shared
    static PollingConditions POLLING_CONDITIONS = new PollingConditions(
            timeout: 30, delay: 1.5, factor: 1.25
    )

    MyResponseContainerDto sendRequestWithRetries(String body, String uri) {
        ExtractableResponse<Response> extractedResponse = null
        POLLING_CONDITIONS.eventually {
           extractedResponse = sendRequest(body, uri).extract()
            assert extractedResponse.statusCode() == 200
        }

        return extractedResponse.as(MyResponseContainerDto.class)
    }

    ValidatableResponse sendRequest(String body, String uri) {
            return RestAssured.given()
                    .contentType(JSON)
                    .body(body)
                    .when()
                    .post("/myApi" + "/" + uri)
                    .then()
                    .log().all()
    }

When I try to run the above code I get:

Expected a condition, but found an assignment. Did you intend to write '==' ? @ line 42, column 12.
              extractedResponse = sendRequest(body, uri).extract()
              ^

Is there a possibility to have an assignment inside the eventually block?


Solution

  • As an alternative to Marcin's suggestion, a simple workaround would be an explicit interaction block:

    package de.scrum_master.stackoverflow.q75663270
    
    import spock.lang.Shared
    import spock.lang.Specification
    import spock.util.concurrent.PollingConditions
    
    class PollingConditionsTest extends Specification {
      @Shared
      PollingConditions POLLING_CONDITIONS = new PollingConditions(
        timeout : 3, delay : 0.2, factor : 1
      )
    
      def myHelper() {
        def extractedResponse = null
        POLLING_CONDITIONS.eventually {
          interaction {
            extractedResponse = "xxx"
            assert extractedResponse.contains("x")
          }
        }
        extractedResponse
      }
    
      def test() {
        expect:
        myHelper() == "xxx"
      }
    }
    

    Please note however that, because the interaction block in your case is not inside then/expect but rather in a helper method, you still need the explicit assert.

    Try it in the Groovy Web Console.

    P.S.: A @Shared field should not be static. It is Spock's better (with regard to Spock spec lifecycle) alternative to static fields.