Introduction

In our REST Assured series, we’ve explored topics like Response Specification, PATCH Requests, and Security Testing, mastering various API testing techniques. Now, we’ll dive into Status Code Validation, a critical practice for verifying HTTP status codes in API responses using REST Assured. This guide covers how to validate common status codes, handle errors, and integrate with reporting tools. It’s designed for beginners and experienced developers, offering clear explanations and practical examples.

Key Point: Status code validation with REST Assured ensures APIs return the expected HTTP status codes, confirming correct behavior for successful requests, errors, or edge cases.

What is Status Code Validation?

Status Code Validation involves checking the HTTP status code in an API response to confirm the outcome of a request. HTTP status codes indicate:

  • 2xx (Success): Request was successful (e.g., 200 OK, 201 Created).
  • 4xx (Client Error): Client-side issues (e.g., 400 Bad Request, 404 Not Found).
  • 5xx (Server Error): Server-side issues (e.g., 500 Internal Server Error).

REST Assured provides methods like statusCode() and Hamcrest matchers to validate status codes, making it easy to test API behavior. We’ll use the public API https://jsonplaceholder.typicode.com, which supports mock responses for various status codes, for our examples.

Setting Up for Status Code Validation

To validate status codes, we’ll use REST Assured, JUnit, and Allure for reporting. The setup mirrors previous posts in the series, with a Maven project configured for testing.

Here’s the pom.xml with required dependencies, styled for Blogger’s XML syntax highlighting:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>rest-assured-tests</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <allure.version>2.27.0</allure.version>
        <aspectj.version>1.9.22</aspectj.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>io.rest-assured</groupId>
            <artifactId>rest-assured</artifactId>
            <version>5.4.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.10.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest</artifactId>
            <version>2.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.15.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.qameta.allure</groupId>
            <artifactId>allure-junit5</artifactId>
            <version>${allure.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.2.5</version>
                <configuration>
                    <argLine>
                        -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
                    </argLine>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjweaver</artifactId>
                        <version>${aspectj.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
            <plugin>
                <groupId>io.qameta.allure</groupId>
                <artifactId>allure-maven</artifactId>
                <version>2.12.0</version>
                <configuration>
                    <reportVersion>${allure.version}</reportVersion>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

No additional setup is needed for https://jsonplaceholder.typicode.com, as it provides consistent responses for status code testing.

Validating Status Codes with REST Assured

Let’s explore how to validate HTTP status codes for various API scenarios, including success, client errors, and server errors.

Example 1: Validating Success Status Codes

Test a GET request to ensure it returns a 200 OK status code.


import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;

@Feature("Status Code Validation")
public class SuccessStatusCodeTest {

    @Test
    @Description("Verify 200 OK status code for GET request")
    public void testGetPostSuccess() {
        RestAssured.baseURI = "https://jsonplaceholder.typicode.com";

        given()
            .log().all()
            .when()
                .get("/posts/1")
            .then()
                .statusCode(200)
                .body("id", equalTo(1))
                .body("title", notNullValue());
    }
}

Explanation:

  • statusCode(200): Validates the response has a 200 OK status.
  • Additional body validations ensure the response content is correct.
  • log().all(): Logs request and response details for debugging.
Important: Always validate status codes alongside response content to ensure the API behaves as expected.

Example 2: Validating Client Error Status Codes

Test a request to a non-existent resource to verify a 404 Not Found status code.


import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;

@Feature("Status Code Validation")
public class ClientErrorStatusCodeTest {

    @Test
    @Description("Verify 404 Not Found status code for non-existent resource")
    public void testGetNonExistentPost() {
        RestAssured.baseURI = "https://jsonplaceholder.typicode.com";

        given()
            .log().ifValidationFails()
            .when()
                .get("/posts/9999")
            .then()
                .statusCode(404)
                .body(isEmptyOrNullString());
    }
}

Explanation:

  • statusCode(404): Expects a 404 Not Found for a non-existent post.
  • body(isEmptyOrNullString()): Verifies the response body is empty, typical for 404 responses.
  • log().ifValidationFails(): Logs details only if the test fails, reducing console clutter.

Example 3: Validating Status Codes with Response Specification

Use a ResponseSpecification to validate status codes consistently across tests.


import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import io.restassured.builder.ResponseSpecBuilder;
import io.restassured.specification.ResponseSpecification;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;

@Feature("Status Code Validation")
public class ResponseSpecStatusCodeTest {

    private ResponseSpecification successSpec;

    @BeforeEach
    public void setup() {
        successSpec = new ResponseSpecBuilder()
            .expectStatusCode(200)
            .expectContentType("application/json")
            .expectBody("id", notNullValue())
            .build();
    }

    @Test
    @Description("Verify status code with Response Specification")
    public void testGetPostWithSpec() {
        RestAssured.baseURI = "https://jsonplaceholder.typicode.com";

        given()
            .log().all()
            .when()
                .get("/posts/1")
            .then()
                .spec(successSpec)
                .body("title", notNullValue());
    }
}

Explanation:

  • successSpec: Defines a specification for 200 OK responses with JSON content and a non-null id.
  • spec(successSpec): Applies the specification to the test.
  • Additional validations (e.g., title) are test-specific.
Pro Tip: Use Response Specifications to centralize status code validation for common scenarios, improving test maintainability.

Example 4: Testing Status Code Ranges

Validate that a status code falls within a range (e.g., 2xx for success) using Hamcrest matchers.


import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;

@Feature("Status Code Validation")
public class StatusCodeRangeTest {

    @Test
    @Description("Verify status code is in 2xx range for POST request")
    public void testPostStatusRange() {
        RestAssured.baseURI = "https://jsonplaceholder.typicode.com";

        String requestBody = "{\"title\": \"Test Post\", \"body\": \"Test Body\", \"userId\": 1}";

        given()
            .contentType("application/json")
            .body(requestBody)
            .log().all()
            .when()
                .post("/posts")
            .then()
                .statusCode(greaterThanOrEqualTo(200))
                .statusCode(lessThan(300))
                .body("title", equalTo("Test Post"));
    }
}

Explanation:

  • statusCode(greaterThanOrEqualTo(200)) and lessThan(300): Ensures the status code is in the 2xx range.
  • Useful for APIs where the exact status code (e.g., 200 vs. 201) may vary.

Integrating with Allure Reporting

Document status code validation tests with Allure, attaching request/response details for clarity.


import io.qameta.allure.Allure;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;

@Feature("Status Code Validation")
public class AllureStatusCodeTest {

    @Test
    @Description("Verify 201 Created status code with Allure reporting")
    public void testPostWithAllure() {
        RestAssured.baseURI = "https://jsonplaceholder.typicode.com";

        String requestBody = "{\"title\": \"Allure Post\", \"body\": \"Test Body\", \"userId\": 1}";
        Allure.addAttachment("Request Body", "application/json", requestBody, ".json");

        Response response = given()
            .contentType("application/json")
            .body(requestBody)
            .log().all()
            .when()
                .post("/posts")
            .then()
                .statusCode(201)
                .body("title", equalTo("Allure Post"))
                .extract().response();

        Allure.addAttachment("Response Body", "application/json", response.asString(), ".json");
    }
}

Explanation:

  • Allure.addAttachment: Attaches the request and response bodies to the Allure report.
  • Run mvn clean test and mvn allure:serve to view the report.

Integrating with CI/CD

Add status code validation tests to a GitHub Actions pipeline for automated execution.

Create or update .github/workflows/ci.yml:


name: REST Assured CI Pipeline

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  build-and-test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up JDK 11
        uses: actions/setup-java@v4
        with:
          java-version: '11'
          distribution: 'temurin'

      - name: Cache Maven dependencies
        uses: actions/cache@v4
        with:
          path: ~/.m2/repository
          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
          restore-keys: ${{ runner.os }}-maven-

      - name: Run tests
        run: mvn clean test

      - name: Generate Allure report
        run: mvn allure:report

      - name: Upload Allure results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: allure-results
          path: target/allure-results

      - name: Publish Allure report
        if: always()
        uses: simple-elf/allure-report-action@v1.7
        with:
          allure_results: target/allure-results
          gh_pages: gh-pages
          allure_report: allure-report

      - name: Deploy report to GitHub Pages
        if: always()
        uses: peaceiris/actions-gh-pages@v4
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: allure-report

Explanation:

  • Runs status code validation tests with mvn clean test.
  • Publishes Allure reports to GitHub Pages for visibility.

Tips for Beginners

  • Know Common Status Codes: Familiarize yourself with HTTP status codes (e.g., 200, 201, 400, 404, 500) to set correct expectations.
  • Use Response Specifications: Centralize status code validations for common scenarios to reduce duplication.
  • Enable Selective Logging: Use log().ifValidationFails() to debug status code mismatches efficiently.
  • Test Edge Cases: Validate status codes for invalid inputs, unauthorized access, or server errors.
Troubleshooting Tip: If a status code validation fails, enable log().all() to inspect the request and response. Check the API documentation for expected status codes.

What’s Next?

This post enhances our REST Assured series by covering status code validation, a foundational skill for API testing. To continue your learning, consider exploring:

  • GraphQL Testing: Testing GraphQL APIs with REST Assured.
  • Advanced Allure Reporting: Customizing reports with environments and categories.
  • End-to-End Testing: Combining REST Assured with Selenium for UI and API testing.
Stay tuned for more testing tutorials!