Cucumber BDD testing using Junit Framework for Rest APIs using RestAssured

Paras Bansal
4 min readApr 17, 2022

Many modern application architectures are now cloud based and even though being could native doesn’t mean microservices architecture, still designing an application based on microservices has many advantages. To reduce complexity one tries to divide whole application into smaller pieces, but then managing so many of them causes more fatigue.

One such challenge it post is how to automate the regression testing for overall application. Even though micro-services ensures that other components are not impacted when one of the service is changed, but most of the times the application architecture allows inter-dependent services. This poses a challenge on ensuring that whole application suite is not broken when new features are released.

This post is similar to my previous post on using Cucumber for UI based testing and its automation with Gitlab CICD. The difference being here I’ll demonstrate how to test Rest APIs and automate them using Gitlab CICD. Also, this time we’ll use the long known Junit framework for our testing.

Let’s touch a little bit on RestAssured. RestAssured brings a lot of simplicity in testing RestApi. Even though the biggest advantage of cucumber is that it provides way of writing test cases in plain English for non-technical people, RestAssured also comes up with its own BDD methods and can be easlily configured for its own scenerios.

A simple example for RestAssured documentation

@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", hasItems(23, 54));
}

Advantages:

  1. You can write test cases in form of Given/When/Then
  2. Parameterize requests
  3. Set different content types
  4. Set authorization headers
  5. Validate different responses and its codes

And a lot of things required for testing RestApis. Pretty much I can say that whatever you need to call a RestApi, all those methods can be configured. You can even map the response to a JAVA POJO and use that to validate your outputs.

Now, let’s jump in our test suite. First thing is configuring gradle to use Junit Platform and produce cucumber reports:

plugins {
id 'java'
id "com.github.spacialcircumstances.gradle-cucumber-reporting" version "0.1.24"
}
test {
useJUnitPlatform()
}

cucumberReports {
outputDir = file('build/reports/')
buildId = '0'
reports = files('build/cucumber-reports/cucumber.json')
}

Also, dependencies:

dependencies {
testImplementation "org.junit.jupiter:junit-jupiter-api:${junitVersion}"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junitVersion}"

testImplementation "io.cucumber:cucumber-java:${cucumberVersion}"

testImplementation "io.cucumber:cucumber-junit:${cucumberVersion}"
testImplementation "org.junit.vintage:junit-vintage-engine:${junitVersion}"

testImplementation 'org.json:json:20160810'
testImplementation 'io.rest-assured:rest-assured:4.5.0'
}

Next is your Runner class:

package com.company.runner;

import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;

@RunWith(Cucumber.class)
@CucumberOptions(
features = {"src/test/resources/featureFiles"},
glue = {"com.company.step.definitions"},
monochrome = true,
dryRun = false,
plugin = {
"json:build/cucumber-reports/cucumber.json",
"rerun:build/cucumber-reports/rerun.txt"
})
public class TestRunner {
}

No methods need to be written here. Cucumber will take all steps from definitions packages and run one at a time.

Let’s see the feature file:

Feature: Dummy Rest Api Functionality Scenarios

Scenario Outline: Dummy Rest Api GET
Given Get Call to "<url>"
Then Response "<responseMessage>" is validated

Examples:
| url | responseMessage |
| /api/v1/employee/1 | Successfully! Record has been fetched. |

If you see, the endpoint is not provided here. You can configure that in the environment or even hard code at the step definitions class as below:

public class DummyRestApiTest {

private Scenario scenario;
private Response response;
private final String BASE_URL="http://dummy.restapiexample.com";

@Before
public void before(Scenario scenarioVal) {
this.scenario = scenarioVal;
}

@Given("^Get Call to \"(.*)\"$")
public void get_call_to_url(String url) throws Exception {
RestAssured.baseURI = BASE_URL;
RequestSpecification req = RestAssured.given();

response = req.when().get(new URI(url));
}

@Then("^Response \"(.*)\" is validated$")
public void response_is_validated(String responseMessage) {
response.then().statusCode(200);
response = response.then().extract().response();
scenario.log("Response Received == " + response.asPrettyString());

JSONObject resJson = new JSONObject(response.asString());
String message = resJson.getString("message");
Assert.assertEquals(responseMessage, message);

}

}

Just to explain, Given method is overridden to call the API and THEN method is overridden to do all sorts of Assertions. As I mentioned before you can map the response to a JAVA POJO and then use RestAssured body method to do all assertions as well.

Here I am using JSONObject, but you can use Jackson, Gson, JsonPath, JsonFlattener, etc. Some examples are provided in this repository.

Lastly, let’s come to running the test suite, reports and Gitlab CIDE automation (not part of repository). This part of post is similar to previous post on UI testing. But for the sake of this post, I’ll cover that here.

Execution is simple, just issue below gradle command —

gradle test

Reports are available at your `build/reports/`

You can also view what happened during the execution of each features:

Finally Gitlab CICD automation.

This is not a part of the repo, but you can always implement using script feature of gitlab. What you need is implement .gitlab_ci.yaml like this:

image: busybox:latesttest:
stage: test
image: gradle:latest
before_script:
- export GRADLE_USER_HOME=`pwd`/.gradle
- chmod +x gradlew
script:
- ./gradlew test
artifacts:
paths:
- build/
expire_in: 1 week
when: always

You can browse the artifacts once the stage is executed and view the reports as well.

That’s all folks. Please leave your comments and I’ll improve this post as much as I can. Gitlab repo is available in below section.

--

--