Automation Testing Part 2: API Testing Using Rest-Assured

In my first post in the automation series, I explained a simple three-step process to start any automation testing. In this post, we will dig into REST API testing, its importance, how to create tests using Rest-Assured and how to integrate them with your ongoing development efforts. In the next post, I will discuss UI testing best practices and principles for mobile applications using Appium.

 

Overview

Making sure your REST API is in tip-top shape is very important, as it is almost always responsible for your applications running smoothly. This, however, comes with a big challenge; how can we ensure that these API services are running as expected? How can we make sure that these services are not degraded with time as more and more code is added? Well, one way is using a tool dedicated to REST API testing and integrating with a proper CI (Continuous Integration) to ensure that they work as anticipated over time. Let’s start by talking about Rest-Assured and how to put it to use.

 

Rest-Assured

Rest-Assured is a Java based DSL (Domain Specific Language) which is most commonly used to test out REST based services. Rest-Assured presents a great advantage because it supports multiple HTTP requests and can validate and/or verify the responses of these requests. These multiple requests include GET, POST, PUT, DELETE, PATCH, OPTIONS and HEAD methods. Given that it supports these various requests, it also allows for them to be constructed with multiple parameters, headers, and their respective body, as well as validating response’s status code, headers, cookies and response time. For the next set of examples, we will be using JSON based requests and responses (application/json). This is very similar for XML requests as well. So now, let’s dig deeper with some code.

Here lies the first step in creating most of your HTTP requests (except for GET calls), your request’s body. Referred to from now on as the service request class, it stores the various JSON values or properties used to create your request body.

 

 import com.google.gson.annotations.Expose;

public class ProductRequest {
    @Expose // Used to serialize and deserialize your JAVA properties to JSON properties
    private int ProductId;
    @Expose
    private String Name;
    @Expose
    private String Description;
    @Expose
    private double Price;

    public int getProductId() {
        return ProductId;
    }

    public void setProductId(int productId) {
        ProductId = productId;
    }

    public String getName() {
        return Name;
    }

    public void setName(String name) {
        Name = name;
    }

    public String getDescription() {
        return Description;
    }

    public void setDescription(String description) {
        Description = description;
    }

    public double getPrice() {
        return Price;
    }

    public void setPrice(double price) {
        Price = price;
    }
}

Next, comes your response. The responses that originate from your various HTTP requests are more than likely to return a body. In this case, GET requests almost always do. For that reason, we can also create a response class to store those values.

 

public class ProductListResponse extends ResponseObject {
    public int Status;
    public int Code;
    public String Message;
    public Data Data;

    public class Data
    {
        public ArrayList Products;
        public int Offset;
        public int Limit;
        public int Total;
    }
    public class Products
    {
        public int ProductId;
        public String Name;
        public String Description;
        public double Price;
    }
}

Now that we have taken care of the request and response bodies, and have created the properties that we expect to receive from them, let’s get our test going. For these examples, we will be using Cucumber. Cucumber uses Gherkin language and BDD testing to run the different scenarios under test.

 

Scenario 1: POST Request

  Scenario Outline: Send a create product request to the server and validate the response
    Given I send a login request to the server
    When I send an insert product request to the server "" "" "" ""
    Then I should receive a status code of 201 created status code
    Examples:
      |  productId  | name      | description | price |
      |    123      | Product 1 | Describe me | 500   |

 

Scenario 2: GET Request

   Scenario: Send a list products request to the server and validate the response
    Given I send a login request to the server
    When I send a get product list request from the server
    Then I should receive the list of products correctly
    And the products id should match expected result

Up next, it’s time to build out our services. Recall that these requests can be constructed with multiple parameters, headers, and other options, as well as various HTTP methods and can hold a response body to be used later to create our assertions. This is essential, as this will mark the difference between a passing or failing API call.

 

Scenario 1: POST Request

    public class ProductServiceObject extends ServiceObject {
    @Inject
    public ProductServiceObject(ContextObject contextObject) {
        super(contextObject);
        this.serviceBuilder.addHeader(new Header("Content-Type", "application/json")); // Adds headers

        // TODO More options available in service builder if needed
        //this.serviceBuilder.setParameter(parameterName, parameterValue); // Adds query parameters
        //this.serviceBuilder.setAuthorization(authorization); // Adds authorization type if needed
    }

    public StatusResponse insertProduct(ProductRequest request) {
        this.serviceBuilder.setUri("http://server-path/api/Product"); // Set request's URI
        String jsonBody = Utilities.createJsonBody(request);
        this.serviceBuilder.setBody(jsonBody); // Set request's body
        StatusResponse response = this.post(); // Call HTTP POST method
        return response; // Status code is stored in response
    }
}

 

Scenario 2: GET Request

  public ProductListResponse getProducts(){
        this.serviceBuilder.setUri("http://server-path/api/Products");
        ProductListResponse response = this.get(); // Call HTTP GET method
        return response; // JSON response is stored in response
    }

 

Then we call on the service object’s methods – this was created in the earlier step inside our step definition class to execute our API calls.

 

Scenario 1: POST Request

@When("^I send an insert product request to the server \"([^\"]*)\" \"([^\"]*)\" \"([^\"]*)\" \"([^\"]*)\"$")
    public void iSendAnInsertProductRequestToTheServer(int productId, String name, String description, double price) throws Throwable {
        productRequest = new ProductRequest();
        productRequest.setProductId(productId);
        productRequest.setName(name);
        productRequest.setDescription(description);
        productRequest.setPrice(price);
        statusResponse = productServiceObject.insertProduct(productRequest); // Call the method under test in service object
    }

 

Scenario 2: GET Request

@When("^I send a get product list request from the server$")
    public void iSendAGetProductListRequestFromTheServer() throws Throwable {
        productListResponse = productServiceObject.getProducts();
    }

 

Finally, with our responses stored and ready to go, we can begin making assertions on the result. These assertions can vary tremendously and are specific to every scenario. However, popular assertions can be validating data inside the response body, validating the presence of a header, or validating a specific status code.

 

Scenario 1: POST Request

 @Then("^I should receive a status code of (\\d+) created status code$")
    public void iShouldReceiveAStatusCodeOfCreatedStatusCode(int statusCode) throws Throwable {
        // Assert status code matches 201 Created
        Assert.assertEquals(statusCode, statusResponse.getStatusCode()); 
    }

 

Scenario 2: GET Request

@Then("^I should receive the list of products correctly$")
    public void iShouldReceiveTheListOfProductsCorrectly() throws Throwable {
        // Assert data in response is not null
        Assert.assertNotNull(productListResponse.Data);
    }

    @And("^the products id should match expected result$")
    public void theProductsIdShouldMatchExpectedResult() throws Throwable {
        // Assert ids are as expected
        Assert.assertEquals(123, productListResponse.Data.Products.get(0).ProductId);
        Assert.assertEquals(456, productListResponse.Data.Products.get(1).ProductId);
        Assert.assertEquals(789, productListResponse.Data.Products.get(2).ProductId);
    }

 

All we need now is to run these tests in an automated way, either in sequence or in parallel. Luckily, given that Rest-Assured is a Java based DSL, it can easily integrate with Gradle, Maven, or other any other build tools to deliver this. Let’s take Gradle for example, we can easily build out a new task which will integrate with Cucumber and the scenarios inside our feature files and execute our tests as needed.

 

Another option that can integrate fairly easily with BDD tests in Java is Cucumber-reporting. After executing the respective task, an HTML report will become available and troubleshooting succeeded and failed executions will be possible. All that’s left is to create a Jenkins job executing our task from our chosen build tool and we have successfully created an automated code base used to validate the correct execution of our REST API.

 

Conclusions

Rest-Assured is not only a great tool to test out REST API calls in a fairly easy manner, it also delivers the opportunity for the Quality Assurance team to develop side by side with developers in any Agile methodology to ensure the highest quality possible of the core architecture that drives their applications. In the next post, I will discuss UI testing best practices and principles for mobile applications using Appium. Can’t wait!

Subscribe to our Blog

Rodolfo Conejo
Rodolfo Conejo
Rodolfo has been a .NET/backend developer for around five years now. He started working on automation testing technologies in 2014 with a focus on UI/UX. Rodolfo enjoys watching movies and solving jigsaw puzzles in his free time.

Deliver off-the-chart results.

WordPress Video Lightbox Plugin