REST API Testing with REST-assured

Learn to perform automated API testing with REST-assured. We will walk through all important concepts with easy-to-follow examples and code snippets.

1. Introduction

REST-assured is an excellent tool for writing automated tests in BDD style development, although it can be used with other styles. It helps in testing a real or mock REST API in a declarative manner, inspired by other dynamic languages such as Ruby and Groovy.

REST-assured has excellent support for testing HTTP methods and uses methods with names of HTTP verbs, such as get() and post() etc. The general syntax for writing a test is:

given()
    ...
    ...
.when()
    ...
    ...
.then()
    ...
    ...;

As a best practice, always add the following static import statements in the test class so we can use all methods directly. These will include almost all the necessary methods for sending the requests and verifying the response with Hamcrest matchers.

import static io.restassured.RestAssured.*;
import static io.restassured.matcher.RestAssuredMatchers.*;
import static org.hamcrest.Matchers.*;

2. Setting Up with Maven

REST-assured depends on the following modules to work with:

<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>rest-assured-common</artifactId>
    <version>5.1.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>rest-assured</artifactId>
    <version>5.1.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>json-path</artifactId>
    <version>5.1.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>xml-path</artifactId>
    <version>5.1.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy</artifactId>
    <version>3.0.12</version>
</dependency>

If we are using Java 9+ then we can include all required dependencies with single inclusion using rest-assured-all.

<dependency>
   <groupId>io.rest-assured</groupId>
   <artifactId>rest-assured-all</artifactId>
   <version>5.1.1</version>
   <scope>test</scope>
</dependency>

3. Testing with REST-assured

Let us learn the basics of testing APIs using examples.

3.1. Setting Default Host, Port and API Root

Although, we can specify the complete API URL, including hostname and port, in each test method but it may not be appropriate for clean code. REST-assured supports baseURI, port and basePath static variables from class RestAssured to configure common URI parts in a single location.

For example, we are building our examples using the public APIs available at reqres. It’s all APIs start with URL https://reqres.in/api/ so we can define the base URI and API path as follows:

@BeforeAll
public static void setup() {
	baseURI = "https://reqres.in/";
	basePath = "/api";
}

3.2. GET APIs

The GET API details are as follows:

HTTP GET /users/2

{
    "data": {
        "id": 2,
        "email": "janet.weaver@reqres.in",
        "first_name": "Janet",
        "last_name": "Weaver"
        ...
        ...
    }
}

Use get() method to invoke the API with path parameters. To verify the response data, we can use the inbuilt methods such as equalsTo(), hasItems(), is() etc.

given()
	.pathParam("id", 2)
.when()
	.get("/users/{id}")
.then()
	.statusCode(equalTo(200))
	.body("data.id", equalTo(2))
	.body("data.email", equalTo("janet.weaver@reqres.in"));

3.3. POST APIs

The demo POST API, we are using the following request.

HTTP POST /users

{
    "name": "lokesh",
    "email": "admin@howtodoinjava.com"
}

To send a POST request with the body, we can send use body() method. To verify the response, we can use the methods as discussed in the previous section.

@Test
public void createUserWithCustomObject_thenSuccess() throws JSONException {
    given()
        .body(new User("lokesh", "admin@howtodoinjava.com"))
        .header(new Header("x-custom-header", "value"))
        .contentType("application/json")
    .when()
        .post("/users")
    .then()
        .statusCode(201)
        .body("id", notNullValue())
        .body("name", equalTo("lokesh"))
        .body("email", equalTo("admin@howtodoinjava.com"));
}

3.4. PUT APIs

For the demo PUT API, we are using the following request. We are updating the email address of employee whose id is 2.

HTTP PUT /users/2

{
    "name": "lokesh",
    "email": "admin@howtodoinjava.com"
}

Sending a PUT request is similar to POST request.

@Test
public void updateUser_thenSuccess() {
    given()
        .body(new User("john", "john@howtodoinjava.com"))
        .contentType("application/json")
    .when()
        .put("/users/2")
    .then()
        .statusCode(200)
        .body("name", equalTo("john"))
        .body("email", equalTo("john@howtodoinjava.com"));
}

3.5. DELETE APIs

The DELETE API is straightforward and down not return any response. It returns response code 204 when the entity is deleted.

HTTP DELETE /users/2

Use delete() method to send HTTP DELETE requests.

@Test
public void deleteUser_thenSuccess() {
    when()
        .delete("/users/2")
    .then()
        .statusCode(204)
        .body(isEmptyOrNullString());
}

4. Building Request Headers and Body

4.1. Request Headers

For sending request headers, use RequestSpecification.header() method.

given()
    ...
    .header(new Header("x-custom-header", "value"))
    .contentType("application/json")
    ...

4.2. Request Body

For sending requests with a request body, we have two options:

  • Either, using JSONObject to build a custom JSON payload. Internally, REST-assured uses JSON.simple to parse the object to JSON payload.
JSONObject requestParams = new JSONObject();
requestParams.put("name", "lokesh");
requestParams.put("email", "admin@howtodoinjava.com");

given()
    .body(requestParams.toString())
    ...
.when()
  • Or, using a custom object that produces the required JSON payload.
given()
    .body(new User("lokesh", "admin@howtodoinjava.com"))
    ...
.when()

Sending XML Request with REST-assured

5. Verifying Response Status and Body

Use any of the Hamcrest matchers to match the parts of the response including response status code, response headers or response body.

given()
    ...
.when()
    ...
.then()
    .statusCode(201)
    .header("x-response-header", equalTo("value"))
    .body("id", notNullValue())
    .body("name", equalTo("lokesh"))
    .body("email", equalTo("admin@howtodoinjava.com"))

6. Extracting Response data

Suppose we want to reuse the data from the response of an API, we can extract it using the extract() method.

String id = given()
        .body(requestParams.toString())
        .contentType("application/json")
    .when()
        .post("/users")
    .then()
        .statusCode(equalTo(201))
        .extract().body().path("id");

7. Logging Response Data

Use the ValidatableResponseLogSpec returned from body() method to log using the Hamcrest log() method.

given()
    ...
.when()
    ...
.then()
    ...
    .log().body();

8. Measuring Response Time and Testing Timeouts

Using the time() method, we can measure the API response time for verifying performance SLAs. It returns the time in milliseconds. To get the time in a specific timeunit, pass the TimeUnit as method argument.

long timeInMs = get("...").time();
long timeInSeconds = get("...").timeIn(TimeUnit.SECONDS);

We can use the time() method with hamcrest matches to test the timeouts.

when().
      get("...").
then().
      time(lessThan(1000L), TimeUnit.SECONDS);

As a best practice, we should test the timeouts when JVM is warmed up. Measuring timeouts in a single test may not give the correct result as it will include a lot of other initializations at the JVM level.

9. Conclusion

In this tutorial, we learned using REST-assured to write automated tests for real API testing. This is an excellent solution for BDD development where we can start writing the API mocks and tests for it, and later we write the actual API implementations.

Happy Learning !!

Sourcecode on Github

Leave a Reply

0 Comments
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions, and frequently asked interview questions.