Decrease boilerplate code for API automation using Rest Assured and BDD

Decrease boilerplate code for API automation using Rest Assured and BDD

In today’s modern development of web and mobile application, the applications need to communicate with the backend in a secure and organized way. This can be achieved by using Application Programming Interface (API). The API is communicating with the backend through the HTTP protocol using the methods GET, POST, PUT, PATCH, DELETE. The RESTful web services are using all protocols, but if you are using an API only for retrieving data, you are going to work mostly with GET methods.

In my API automation solution example I’m using an API for retrieving data from the server using the GET method. The API that I’m using for my solution is a soccer statistics API that could be found on the following link. Before you start working on your API automation, first make sure that the API requests are working properly by using Postman and executing the API URL. If you would like to use the same API that I have used in my demo, you would have to request an API key through the following link.

Getting started

For my demo I’m using:

  • InteliJ CE.
  • Java as programming language.
  • Cucumber, for running the scenarios and the BDD approach.
  • Rest Assured, for validating the API request.

The reason why I have chosen rest assured is that it BDD approach by its nature, and also supports JSON, XML responses, and various authentications.  If you are more interested in Rest Assured, you can check the following URL for more details. Here is one example of a automation test using Rest Assured from the official site:

@Test public void lotto_resource_returns_200_with_expected_id_and_winners() {
when(). get(“/lotto/{id}”, 5).
then(). statusCode(200).
body(“lotto.lottoId”, equalTo(5), “lotto.winners.winnerId”, containsOnly(23, 54));
}

At this point you are asking yourself, “Why the heck I would have to use BDD approach, when I can use JUnit and Rest Assured only.” At this point you are right it is a simple test, and this suits perfect, but if we have 500 tests that we are going to automate, and if we have to write each test beginning with when().then() we are going to have to write a lot of boilerplate code, and not to imagine the time required for maintaining the code. Another overhead is if we have to add additional parameters to the API before invoking the API methods.

Hands on details

The demo has simple logic for separating the logic in order to reduce the boilerplate code when writing the API automation tests. The responsibility is divided in the following classes:

  • ApiHelper, this class is used for initializing and destroying the Endpoint class.
  • Endpoint, this class is responsible for setting the header, sending API request, and reading the API response.
  • AppConfig, this class is used for reading the configuration of the API automation suite.
  • CompetitionsSteps, this class is used for implementing the logic of the step definitions defined in the feature file.
  • api.properties, is used for defining the configuration for the automation suite.
  • competitions.feature, this is the feature file that contains the scenarios and the corresponding steps.

Lets have a look at our first scenario:

@Competitions
Scenario: Validate competition with id 444
  Given The API endpoint "/competitions/444" to retrieve the competitions data
  Then Validate the caption of the competition is "Campeonato Brasileiro da Série A"

As you can see we have two scenario steps, in the given step I’m setting the header and sending the request to the API endpoint, and in the second step I’m reading and validating the response. Here is the definition of these steps:

@Given ("^The API endpoint \"(.*)\" to retrieve the competitions data$")
public void givenTheAPIEndpointToRetrieveTheData(String endpointUrl) throws Throwable{
    apiHelper.getEndpoint().sendRequest(endpointUrl, Endpoint.RequstMethod.GET);
}

@Then ("^Validate the caption of the competition is \"(.*)\"$")
public void thenValidateTheCaptionOfTheCompetitionIs(String competitionCaption) throws Throwable{
    apiHelper.getEndpoint().readResponse().body("caption", equalTo(competitionCaption));

}

Ok, so far so good, but how can you reduce the boilerplate code in this way compared to the first example?
Let me show you with another example, lets say we want to validate the links in the competitions response, but we don’t want to write the boilerplate code, we just want to validate the response. Let’s have a look in the following scenario:

@Competitions
Scenario: Validate competition links with id 444
  Given The API endpoint "/competitions/444" to retrieve the competitions data
  Then Validate the competition links "self;teams;fixtures;leagueTable"

With the following approach we have reused the previous request for setting the API header, and sending the API request, and by adding the new validation method we have implemented the logic for validating the competitions links. When using this approach is very helpful for newcomers to understand what we are trying to achieve with our scenario. Here is the code of the validation for the second scenario:

@Then ("^Validate the competition links \"(.*)\"$")
public void thenValidateTheCompetitionLinks(String links){
    String[] linksArray = links.split(";");
    String endpointUrl = apiHelper.getEndpoint().getEndpointUrl();

    for(int i = 1; i < linksArray.length; i++){
        String link = String.format("%s/%s", endpointUrl, linksArray[i]);
        String jsonPath = String.format("_links.%s.href", linksArray[i]);
        apiHelper.getEndpoint().readResponse().body(jsonPath, equalTo(link));
    }
}

Bonus

Let’s say we want to validate the structure of our JSON response, but we want to this in a minimalistic possible way. The answer to this is using JSON schema for validating the JSON response. At the moment you are probably asking yourself what is a validation JSON schema, and how to create it. Don’t worry I have the answer for you, you can create the JSON validation schema by using jsonschema.net. Lets see an example how we can validate the JSON schema of our JSON response. Consider the following scenario:

@Competitions
Scenario: Validate competition response schema
  Given The API endpoint "/competitions/444" to retrieve the competitions data
  Then Validate the compeition response using json schema with name "competition-schema"

And here is the implementation of the validation method:

@Then ("^Validate the compeition response using json schema with name \"(.*)\"$")
public void thenValidateTheCompetitionResponseUsingJsonSchema(String schemaName){
    String competitionSchema = schemaReader.readJsonSchema(schemaName);
    apiHelper.getEndpoint().readResponse().body(matchesJsonSchema(competitionSchema));
}

As you can see we have used only two lines of code to validate the JSON schema of the API response. In the following step I have separated the logic for reading the JSON schema in a SchemaReader class. The benefit of using an JSON schema for validating the JSON response is that we don’t have to use additional logic for validating the JSON values by our selfs.

Final thoughts

I hope you have found this post useful, and helpful in your automation progress. You can find the demo in the following link. And if you like this post, don’t forget to share it with your friends 🙂

 

One thought on “Decrease boilerplate code for API automation using Rest Assured and BDD

  1. Pingback: Testing Bits – 12/10/17 – 12/16/17 | Testing Curator Blog

Leave a Reply

Your email address will not be published. Required fields are marked *