Introduction
In our previous post, we explored Authentication in REST Assured, learning how to secure API requests. Now, we’ll dive into Response Validation, a critical aspect of API testing that ensures APIs return the expected data and behave correctly. This guide is designed for beginners and experienced developers, providing clear explanations and practical examples to master response validation in REST Assured.
Key Point: Response validation in REST Assured allows you to verify the status code, headers, and body of API responses to ensure they meet expected criteria.
What is Response Validation?
Response Validation involves checking the HTTP response from an API to confirm it matches the expected outcome. This includes validating:
- Status Code: Ensures the request was processed correctly (e.g., 200 OK, 404 Not Found).
- Headers: Verifies response headers like
Content-Type
or custom headers. - Body: Checks the content of the response, such as JSON or XML fields, for correctness.
REST Assured provides a powerful Given-When-Then syntax and Hamcrest matchers to validate responses efficiently.
Validating Responses in REST Assured
Let’s explore how to validate API responses using REST Assured, with examples using the public API https://jsonplaceholder.typicode.com
.
Option 1: Validating Status Code
The simplest validation checks the HTTP status code to ensure the request was successful.
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
public class StatusCodeValidationTest {
@Test
public void testStatusCode() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
given()
.when()
.get("/posts/1")
.then()
.statusCode(200);
}
}
Explanation:
statusCode(200)
: Verifies the response has a 200 OK status, indicating success.- Use other status codes like 404 (Not Found) or 500 (Server Error) based on the test scenario.
Important: Always validate the status code first, as it indicates whether the request was processed correctly before checking the response body or headers.
Option 2: Validating Response Body (JSON)
Validate specific fields in a JSON response using Hamcrest matchers.
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
public class JsonBodyValidationTest {
@Test
public void testJsonBody() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
given()
.queryParam("userId", 1)
.when()
.get("/posts")
.then()
.statusCode(200)
.body("[0].userId", equalTo(1))
.body("[0].title", notNullValue())
.body("size()", greaterThan(0));
}
}
Explanation:
body("[0].userId", equalTo(1))
: Verifies the first post’suserId
is 1.body("[0].title", notNullValue())
: Ensures the first post’stitle
exists.body("size()", greaterThan(0))
: Confirms the response array contains at least one item.- Use dot notation (e.g.,
[0].field
) to navigate JSON structures.
Option 3: Validating Response Headers
Validate response headers to ensure they match expected values, such as Content-Type
.
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
public class HeaderValidationTest {
@Test
public void testHeaders() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
given()
.when()
.get("/posts/1")
.then()
.statusCode(200)
.header("Content-Type", containsString("application/json"))
.header("Server", notNullValue());
}
}
Explanation:
header("Content-Type", containsString("application/json"))
: Verifies the response is JSON.header("Server", notNullValue())
: Ensures theServer
header exists.
Option 4: Using Request Specification for Consistent Validation
Use a Request Specification to apply common settings, and validate responses consistently.
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.specification.RequestSpecification;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
public class ValidationWithSpecTest {
private static RequestSpecification requestSpec;
@BeforeAll
public static void setup() {
requestSpec = new RequestSpecBuilder()
.setBaseUri("https://jsonplaceholder.typicode.com")
.addHeader("Accept", "application/json")
.build();
}
@Test
public void testValidationWithSpec() {
given()
.spec(requestSpec)
.pathParam("postId", 1)
.when()
.get("/posts/{postId}")
.then()
.statusCode(200)
.body("id", equalTo(1))
.body("title", notNullValue())
.header("Content-Type", containsString("application/json"));
}
}
Explanation:
RequestSpecBuilder
: Sets the base URI andAccept
header.spec(requestSpec)
: Applies the specification to the test.- The test validates status code, JSON body, and headers.
Pro Tip: Combine Request Specifications with response validation to enforce consistent checks across tests, improving maintainability.
Step 1: Extracting and Validating Response Data
Extract the response for advanced validation or processing.
import io.restassured.RestAssured;
import io.restassured.response.Response;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
public class ExtractResponseTest {
@Test
public void testExtractAndValidate() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
Response response = given()
.when()
.get("/users/1")
.then()
.statusCode(200)
.extract().response();
String name = response.path("name");
String email = response.path("email");
// Custom validation
assert name != null && !name.isEmpty();
assert email.contains("@");
System.out.println("User Name: " + name + ", Email: " + email);
}
}
Explanation:
extract().response()
: Extracts the full response.response.path()
: Retrieves specific fields for custom validation.- This approach is useful for complex validations or logging.
Step 2: Validating Complex JSON Structures
Validate nested JSON structures or arrays using dot notation or Hamcrest matchers.
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
public class ComplexJsonValidationTest {
@Test
public void testComplexJson() {
RestAssured.baseURI = "https://jsonplaceholder.typicode.com";
given()
.when()
.get("/users/1")
.then()
.statusCode(200)
.body("address.street", notNullValue())
.body("address.geo.lat", instanceOf(String.class))
.body("company.name", containsStringIgnoringCase("inc"));
}
}
Explanation:
body("address.street", notNullValue())
: Validates a nested field in the JSON response.body("address.geo.lat", instanceOf(String.class))
: Checks the type of a nested field.body("company.name", containsStringIgnoringCase("inc"))
: Verifies a substring in a field, case-insensitive.
Step 3: Verify Setup with pom.xml
Ensure your pom.xml
includes dependencies for REST Assured and JUnit:
<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>
</dependencies>
Run the tests using mvn test
or your IDE’s test runner to confirm the setup.
Tips for Beginners
- Start with Status Codes: Always validate the status code before checking headers or body.
- Use Hamcrest Matchers: Leverage matchers like
equalTo
,notNullValue
, orcontainsString
for flexible validation. - Check API Documentation: Understand the expected response structure and fields.
- Enable Logging: Use
RestAssured.enableLoggingOfRequestAndResponseIfValidationFails()
to debug validation failures.
Troubleshooting Tip: If validations fail, check the response structure using logging or tools like Postman. Ensure your JSON paths and expected values match the API’s response.
What’s Next?
In the next post, we’ll cover Data-Driven Testing, exploring how to run REST Assured tests with multiple data sets for comprehensive API testing. Stay tuned for more hands-on examples!