API Test Automation with RestAssured Library and Cucumber BDD Framework
Tags: frameworkssuchastestngjunit
Published: 2024-05-18 02:54:30

Introduction to Rest Assured Library


REST (Representational State Transfer) is an architecture that consumes HTTP calls for inter-system communication where a client can access the server resource with a unique URI and a response of the resource is returned. The URI of the resource acts as a resource identifier and HTTP operations like GET, POST, PUT, PATCH, DELETE can be performed on the resource.

REST Assured is a Java library that leverages developing powerful maintainable tests for Restful APIs with domain specific language(DSL). Let’s discuss some of the salient features of the Rest Assured Library:

It’s an open source application, hence, there’s no license cost
Uses the [commonly used programming language](https://www.pcloudy.com/blogs/top-automation-programming-languages/) Java 
Makes API testing and validation of Rest services easy and smooth
GPath is used to traverse through the response which is great for both XML and JSON response read
Validations on JSON schema can be applied
Effortless integration can be done with other testing [frameworks such as TestNG, JUnit](https://www.pcloudy.com/blogs/testng-vs-junit-testing-framework-which-one-is-better/) etc
Supports API automation for all types of HTTP methods such as GET, POST, PUT, DELETE, PATCH etc
Provides support of BDD Gherkin language which leads to clean coding and easy readability

Introduction to Cucumber Framework


Cucumber is an [open source testing framework](https://www.pcloudy.com/blogs/the-best-java-testing-frameworks-to-focus-in-2021/) that supports Behavior Driven Development (BDD) and is a widely used framework that testers leverage to write test cases in simple English language called Gherkin.

To make the testing process and testing flow easily understandable by non-techies, many organizations want to integrate Cucumber framework with Selenium or Rest Assured for application automation. Since Cucumber allows writing tests and scenarios in simple English plain text, it becomes a primary advantage for many team members who are Business Analysts, Project Managers, Manual Testers and for any other non-technical persons to view and understand the testing workflow with much ease. Cucumber is //.[known as Behavior Driven Development (BDD) framework as it can help anyone to grab the functional behavior of an application by just reading out the feature file.



Cucumber framework is basically divided in three different components:

Feature File: This file provides high level information of an application under test in form of test feature, test scenarios, test tags, test cases, test data etc. Below are few a components that are used to create feature file:
Feature- Defines the feature that is planned to be tested along with its objective.
Scenario- Defines the particular test scenario for which test flow has to be created.
Scenario Outline- Defines the particular test scenario against different test data provided in a tabular structure separated by pipe symbol( | )
Tags- Defines a name of the tag for each scenario which helps in organizing or grouping all the test scenarios of the feature file. Tags can be used on the above Feature keyword as well to indicate which feature file needs to be executed.
Given- Defines pre-condition of a particular test scenario
When- Defines an action or interaction with an application yet to be performed
And- Defines extra action related linked with previous action
Then- Defines the expected output of the test and the post action to be performed
Examples- Defines set of test data for the test case written in “Scenario Outline”
Step Definition File: The step definitions file is created to link all the feature file test case steps to code. Few annotations like Given, When, Then etc are used in step definition files to map the test case steps for their code execution. For a test case to be executed, the annotated description must match the test step mentioned in the feature file.
Test Runner File: This file acts as a driver file for your test suite that drives or runs the step definition files based on feature files. The Test Runner file basically consists of the paths to your feature and step definition file along with the tags to be executed and required for cucumber based test reporting. For cucumber based HTML reporting, it also provides you an option to add a plugin to generate insightful reports.

Integrating Rest Assured Library with Cucumber Framework


Now that we are aware of the Rest Assured library and Cucumber framework, lets practically understand how we can create the test scenarios and learn the steps for api testing against different sets of test data. To integrate the rest assured library with the cucumber framework, we would need to create different files like feature, step definition and runner file as discussed earlier. 

Before moving forward, let’s create a simple maven project and import all the dependencies of the rest assured library and of the cucumber framework in the pom.xml file.



<dependency>
  <groupId>info.cukes</groupId>
  <artifactId>cucumber-java</artifactId>
  <version>1.2.5</version>
</dependency>

  <dependency>
  <groupId>info.cukes</groupId>
  <artifactId>cucumber-jvm-deps</artifactId>
  <version>1.0.5</version>
  <scope>test</scope>
  </dependency>
 
  <dependency>
  <groupId>info.cukes</groupId>
  <artifactId>cucumber-testng</artifactId>
  <version>1.2.5</version>
  <scope>compile</scope>
  <exclusions>
  <exclusion>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  </exclusion>
  </exclusions>
  </dependency>
 
  <dependency>
  <groupId>net.masterthought</groupId>
  <artifactId>cucumber-reporting</artifactId>
  <version>5.0.2</version>
  </dependency>
 
    <dependency>
  <groupId>io.rest-assured</groupId>
  <artifactId>rest-assured</artifactId>
  <version>4.3.2</version>
  <scope>test</scope>
  </dependency>

  <dependency>
  <groupId>io.rest-assured</groupId>
  <artifactId>json-path</artifactId>
  <version>4.3.2</version>
  <scope>test</scope>
  </dependency>


  <dependency>
  <groupId>io.rest-assured</groupId>
  <artifactId>xml-path</artifactId>
  <version>4.3.2</version>
  <scope>test</scope>
  </dependency>


  <dependency>
  <groupId>io.rest-assured</groupId>
  <artifactId>json-schema-validator</artifactId>
  <version>4.3.2</version>
  <scope>test</scope>
  </dependency>

      <dependency>
  <groupId>org.hamcrest</groupId>
  <artifactId>hamcrest-all</artifactId>
  <version>1.3</version>
  <scope>test</scope>
  </dependency>


While working with cucumber framework, it is always recommended to have a different package for different cucumber components, this helps in developing a better project hierarchy and ease the process of understanding the test suite.

Cucumber Framework
Feature File: 

Reqres_api_test.feature



Feature: Test Reqres user api’s with rest assured library and cucumber framework

@SmokeTest
Scenario Outline: Reqres GET API test

Given the valid endpoint to fetch users
When the request is send to server with page number as “<page>”
Then validate the response of first user record having email as “<emailID>”

Examples:
    |page|emailID |
    | 2  |michael.lawson@reqres.in|
    | 1  |george.bluth@reqres.in|

@SmokeTest
Scenario Outline: Reqres POST API test

Given the valid endpoint with payload to create user
When the request is send to the server
Then the new user must be created with name as “<username>”

Examples:
    |username|
    | john  |



With the above feature file, the goal is to perform parameterization testing with multiple test data. “Examples” keyword is used when test data has to be created and the test data is created with a pipe symbol as delimiter( | ). To add a parameter in a test step of a feature file, the syntax is “<variableName>”, the same has been used above. Further, the same variable name is used in the first row of Examples to segregate the test data according to specific parameters. 

Step Definition File:

GetApiTest.java



package stepDefinitions;

import static io.restassured.RestAssured.given;
import org.testng.Assert;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import io.restassured.response.Response;

public class GetApiTest {
   
    Response response;
   
    @Given("^the valid endpoint to fetch users$")
    public void setupEndpoint()
    {
  RestAssured.baseURI="https://reqres.in/";
    RestAssured.basePath="/api/users";
    }
   
   
    @When("^the request is send to server with page number as \"([^\"]*)\"$")
    public void sendRequest(int pageNumber)
    {
  response = given().
    queryParam("page",pageNumber).
    when().
    get().
    then().
    contentType(ContentType.JSON).
    extract().response();  
    }
   
   
    @Then("^validate the response of first user record having email as \"([^\"]*)\"$")
    public void validateUserData(String emailID)
    {
  String userEmail = response.path("data[0].email");
  Assert.assertEquals(userEmail, emailID);  
    }

}


PostApiTest.java



package stepDefinitions;

import static io.restassured.RestAssured.given;

import java.util.HashMap;

import org.testng.Assert;

import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import io.restassured.response.Response;

public class PostApiTest {
   
Response response;
public HashMap<Object,Object> map=new HashMap<Object,Object>();
   
    @Given("^the valid endpoint with payload to create user$")
    public void setupEndpointAndPostData()
    {
  RestAssured.baseURI="https://reqres.in/";
    RestAssured.basePath="/api/users";
 
    map.put("name","john");
    map.put("job", "Software Developer");
    }
   
   
    @When("^the request is send to the server$")
    public void sendRequest()
    {
  response = given()
    .contentType(ContentType.JSON)
    .body(map)   
    .when()
    .post()
    .then()
    .statusCode(201).contentType(ContentType.JSON).
    extract().response();
    }
   
   
    @Then("^the new user must be created with name as \"([^\"]*)\"$")
    public void validateResponse(String name)
    {
  String userName = response.path("name");
  Assert.assertEquals(userName, name);  
    }

}


Above, we have created two step definition files as per 2 scenarios mentioned in the feature file, one for GET api validation and the other for POST api validation.

In our step definition file, we have written an execution code for each test step defined in the feature file. This is the file that integrates rest assured with cucumber framework as all the api’s are being validated here. The test steps written in the feature file have to be the same in the annotated descriptions with the defined way of using parameters. Further, we have used a bit of TestNG here to assert the server response.

Runner File:

Runner.java



package testRunner;

import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import cucumber.api.CucumberOptions;
import cucumber.api.testng.CucumberFeatureWrapper;
import cucumber.api.testng.TestNGCucumberRunner;



@CucumberOptions(
    features = "src/test/java/FeatureFile",
    glue = {"stepDefinitions"},
    tags = {"@SmokeTest"},
    format = {
                "pretty",
                "html:target/cucumber-reports/cucumber-pretty",
                "json:target/cucumber-reports/CucumberTestReport.json",
                "rerun:target/cucumber-reports/rerun.txt"
        },plugin = "json:target/cucumber-reports/CucumberTestReport.json")


public class Runner {
   
    private TestNGCucumberRunner testNGCucumberRunner;
   
    @BeforeClass
    public void setUp() throws Exception
    {
  testNGCucumberRunner = new TestNGCucumberRunner(Runner.class);
    }
   
   
    @Test(dataProvider="features")
      public void my_test(CucumberFeatureWrapper cucumberFeature)
    {
  testNGCucumberRunner.runCucumber(cucumberFeature.getCucumberFeature());
    }
   
   
    @DataProvider
public Object[][] features()
    {
  return testNGCucumberRunner.provideFeatures();  
    }
   
   
    @AfterClass
public void tearDown()
    {
  testNGCucumberRunner.finish();   
    }

}

Code Walkthrough: 
In our cucumber test runner file, we have a CucumberOptions annotation that accepts parameters like path of the feature file and step definition file along with the tags name and reporting format along with HTML reporting plugin. 

To integrate Cucumber framework with Rest Assured Library and TestNG framework, we have used a cucumber framework predefined class called “TestNGCucumberRunner” which provides various methods such as runCucumber, provideFeatures, finish etc. “CucumberFeatureWrapper” is an interface used in a parameter of the Test annotated method for making TestNG report more descriptive.

TestNG.xml



<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">

<suite name="TestNG-Cucumber Suite" thread-count="10" parallel="tests">
    <test name="Apple test">
  <classes>
  <class name="testRunner.Runner" />
  </classes>
    </test>
</suite>


This is a TestNG xml file for configuring the execution of the test suite. We have used Runner java class to execute the api tests, once successfully executed, the report can be visualized from target directory -> cucumber-reports -> cucumber-pretty -> index.html.