Re: [rest-assured] Reuse a Response with new ResponseSpecifications for a Cucumber test suite

625 views
Skip to first unread message

Johan Haleby

unread,
Apr 26, 2013, 2:01:10 AM4/26/13
to rest-a...@googlegroups.com
Hi, 

The syntax if RA is not optimal here, I hope I find time to change it to given-when-then in time for the 2.0 release. The problem is that RA expects a response specification before the request is made so on top off my head I can't think of any better way. The reason for the given-then-when syntax was a technical limitation that I ran into when I started out with the project which I've now managed to resolve. 

Regards,
/Johan

On Thu, Apr 25, 2013 at 5:15 PM, James Christian <j.g.ch...@gmail.com> wrote:
Might be missing something obvious here so apologies if I'm being dumb!

I have a number of assertions I'd like to run against a response and I can see how simple this is to do by chaining with the RA DSL or building up a RequestSpecification with multiple assertions and finishing off with a get() or post(). 

To get this to work with the Cucumber way of running tests, I have tweaked the standard Given-When-Then pattern to Given-Then-When.  So I have something like...

# my.scenario
Scenario:
    Given I specify a value of 2 and action of double
    Then the response code should be 200
    And the result should be 4
    When I submit to my Calculator API


# My.java
...

    RequestSpecification requestSpec = RestAssured.with();

    @Given("^I specify a value of (\\d+) and action of (double|halve)$")
    public void I_specify_a_value_and_action(int value, String action) throws Throwable {
        requestSpec.given().param("value", value);
        requestSpec.given().param("action", action);
    }

    @Then("^the response code should be (\\d+)$")
    public void the_response_code_should_be(int respCode) throws Throwable {
        requestSpec.expect().statusCode(200);
    }

    @Then("^the result should be (\\d+)$")
    public void the_result_should_be(int expectedResult) throws Throwable {
        requestSpec.expect().body("calc.result", equalTo(expectedResult));
    }

    @When("^I submit to my Calculator API$")
    public void submit_to_my_Calculator_API() throws Throwable {
        requestSpec.when().get("http://myserver/CalcService");
    }

...


As expected Cucumber runs through the scenario steps in the order defined in my.scenario and the all the assertions are performed in the final "When" step.    So we've achieved a number of good things - separation of scenario and step definitions, reusable step definitions, using RestAssured to simplify the API calls and running assertions, etc.

However, as all the assertions are run in the "When" step, the existing Cucumber reporting and tooling will claim the "Then' steps passed successfully so it's not immediately obvious what has failed.  The user is expected to dig in to the "When" step failure report and decipher all the assertion fails in one.

Ideally we'd like to see the relevant "Then" steps failing in the Cucumber reports where the contained RestAssured assertions fail.  To do this I thought we might be able to revert back to the traditional Given-When-Then pattern and re-use the Response object generated in the When step in each of the Then steps.  I want to avoid making the request multiple times in case it modified resource state.

In my head Maybe something like..


# my2.scenario
Scenario:
    Given I specify a value of 2 and action of double
      When I submit to my Calculator API 
 And the result should be 4 
 Then the response code should be 200


# My2.java
...

    Response response;

    @Given("^I specify a value of (\\d+) and action of (double|halve)$")
    public void I_specify_a_value_and_action(int value, String action) throws Throwable {
        requestSpec.given().param("value", value);
        requestSpec.given().param("action", action);
    }

    @When("^I submit to my Calculator API$")
    public void submit_to_my_Calculator_API() throws Throwable {
        response = requestSpec.when().get("http://myserver/CalcService"); // <-- Stashing the response
    }

    @Then("^the response code should be (\\d+)$")
    public void the_response_code_should_be(int respCode) throws Throwable {
        RequestSpecification requestSpec = RestAssured.with();  
        requestSpec.expect().statusCode(200).when().withResponse(response); // <-- Recycling the response (I've made up withResponse())
    }

    @Then("^the result should be (\\d+)$")
    public void the_result_should_be(int expectedResult) throws Throwable {
        RequestSpecification requestSpec = RestAssured.with();
        requestSpec.expect().body("calc.result", equalTo(expectedResult)).when().withResponse(response); // <-- Recycling the response (I've made up withResponse())
    }


...


This code assumed a lot; i.e. that the Response object is fully populated with the result of the GET.


Is there an existing or better way I could achieve my objective?

Thanks

J


--
You received this message because you are subscribed to the Google Groups "REST assured" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rest-assured...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

James Christian

unread,
Apr 30, 2013, 10:58:31 AM4/30/13
to rest-a...@googlegroups.com
Thanks for your response.

Thinking about it, in some circumstances it may be preferable to adopt G-T-W as Cucumber breaks execution on Step failure - so you wouldn't get a listing of all assert failures as you do with my first example.

I guess the ultimate flexibility would be to enable RA to support both GWT and GTW - look forward to seeing it!

Thanks again

J

James Christian

unread,
Jul 1, 2013, 8:37:37 AM7/1/13
to rest-a...@googlegroups.com
Just a quick update to say we've managed to work out a way to define Given When Then style tests.

Ian submitted this patch that exposes the validate(Response) method on the ResponseSpecification.  We stash the Response object in the When step and in the Thens we construct the assert using a ResponseSpecification and call validate on it - passing in the stashed Response.  e.g.

// Given Step
// Perform the request
Response response = given(reqSpec, ANY_RESPONSE).get("/api/foo");
 
// Stash the response so the Then steps can reference it
scenarioStash.put("foo-api-response", response);


... 
// Then Step 1
// Define the first assert 
ResponseSpecification responseSpec = new ResponseSpecBuilder().expectBody("my-field", equalTo("my-expected-result")).build();

// Validate the assert against the previously stashed Response 
responseSpec.validate((Response)scenarioStash.get("foo-api-response"));
 
... 
// Then Step 2
// Define the second assert 
ResponseSpecification responseSpec = new ResponseSpecBuilder().expectBody("my-other-field", equalTo("my-other-expected-result")).build();

// Validate the assert against the previously stashed Response 
responseSpec.validate((Response)scenarioStash.get("foo-api-response"));


One caveat you may have spotted... to allow reuse of the Response an assert must be performed.  Therefore we pass a dummy 'anyResponse' object in the initial given() call in the When step

private static final ResponseSpecification ANY_RESPONSE = new ResponseSpecBuilder().expectBody(anything()).build();

Johan Haleby

unread,
Jul 1, 2013, 9:56:10 AM7/1/13
to rest-a...@googlegroups.com
It ought to be simple to fix so that you don't need the "ANY_RESPONSE" object, it's actually already added as issue 56

/Johan
Reply all
Reply to author
Forward
0 new messages