Asserting JSON Responses with REST-Assured in Java
This article explores how to use Java REST-assured to efficiently assert JSON responses in REST API testing. REST-assured is a Java library specifically designed for testing REST APIs, allowing developers to make HTTP calls and verify responses with ease. When working with APIs, verifying JSON response structures and values is essential to ensure data accuracy and consistency across applications. The article will also focus on asserting properties within arrays in JSON responses.
1. Sample JSON Structure
To understand how we can assert JSON responses effectively, let’s start with an overview of a sample JSON structure that represents a typical API response. This structure will serve as the basis for illustrating different assertion techniques using Java REST-assured.
Consider the following JSON response from an API endpoint that provides user session information:
{ "activeSession": true, "token": "abc123", "details": [ { "accountType": 2, "accountDescription": "Premium", "username": "mr_fish", "clientId": 42 } ] }
This JSON has an array field details
, and our goal is to verify the values of the properties within that array.
Here is a controller class, SessionInfoController
, to handle the HTTP request and produce the above JSON response.
@RestController @RequestMapping("/api") public class SessionInfoController { @GetMapping("/session-info") public Map<String, Object> getSessionInfo() { Map<String, Object> sessionInfo = Map.of( "activeSession", true, "token", "abc123", "details", Collections.singletonList( Map.of( "accountType", 2, "accountDescription", "Premium", "username", "mr_fish", "clientId", 42 ) ) ); return sessionInfo; } }
2. Setting Up REST-assured
To begin, it’s essential to have REST-assured configured in the project. Adding REST-assured to the project dependencies will enable testing of JSON responses. For configuration with Maven, include the following dependency in the pom.xml
file:
<dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured</artifactId> <version>5.4.0</version> <scope>test</scope> </dependency>
3. Example Test: Asserting Array Properties
Consider an endpoint /session-info
that returns this JSON data. The test will be structured to validate each property’s values precisely. Begin by setting REST-assured’s base URI to point to the API server. Then, write the test case using REST-assured’s given()
, when()
, and then()
methods to define assertions for each JSON field, ensuring the response data aligns with expected values.
The body()
method in REST-assured is essential for checking specific fields in a JSON response. Used with equalTo()
, it verifies that each field has the correct value, ensuring the data is accurate and consistent.
public class SessionInfoTest { @BeforeAll public static void setup() { RestAssured.baseURI = "http://localhost:8080/api"; } @Test public void testSessionInfoResponse() { given() .contentType(ContentType.JSON) .when() .get("/session-info") .then() .statusCode(200) .body("activeSession", equalTo(true)) .body("token", equalTo("abc123")) .body("details", hasSize(1)) .body("details[0].accountType", equalTo(2)) .body("details[0].accountDescription", equalTo("Premium")) .body("details[0].username", equalTo("mr_fish")) .body("details[0].clientId", equalTo(42)); } }
Here’s an explanation of each assertion.
body("activeSession", equalTo(true))
: Asserts that theactiveSession
property istrue
.body("token", equalTo("abc123"))
: Verifies that thetoken
field matches the expected string"abc123"
.body("details", hasSize(1))
: Checks that thedetails
array has exactly one object.body("details[0].accountType", equalTo(2))
: Asserts that theaccountType
field in the first element ofdetails
is2
.body("details[0].accountDescription", equalTo("Premium"))
: Verifies theaccountDescription
field is"Premium"
.body("details[0].username", equalTo("mr_fish"))
: Checks theusername
field is"mr_fish"
.body("details[0].clientId", equalTo(42))
: Asserts that theclientId
field in the first element ofdetails
is42
.
3.1 Asserting the Entire JSON Body as a String
REST-assured provides the .extract()
method, which allows us to capture the response after performing assertions. This approach is useful for checking the full structure and content of the response in one assertion.
@Test public void testWholeJsonBody() { // Extract the JSON response body as a string String body = given() .get("/session-info") .then() .extract() .body() .asString(); // Assert the entire JSON structure as a single string assertThat(body) .isEqualTo("{\"details\":[{\"accountDescription\":\"Premium\",\"clientId\":42,\"username\":\"mr_fish\",\"accountType\":2}],\"activeSession\":true,\"token\":\"abc123\"}"); } }
- Extracting JSON as String: The
given().get("/session-info").then().extract().body().asString()
retrieves the JSON response body from the/session-info
endpoint as a single string. - Asserting the JSON String: Using
assertThat(body).isEqualTo(...)
, we directly compare the extracted JSON string to the expected JSON string to ensure that the entire response body matches exactly.
4. Asserting With JSONAssert
Comparing JSON as plain strings can lead to test failures due to field ordering differences. We might encounter errors which indicate that the actual JSON response has fields in a different order than expected. JSON objects do not enforce a specific order for fields, so this discrepancy can occur without affecting the content’s meaning.
To handle this, we can use JSONAssert to perform a relaxed comparison that ignores the order of fields. Here’s how to modify the test to use JSONAssert for an order-independent assertion.
@Test void whenGetBody_thenCanCompareByWholeString() throws Exception { // Extract the JSON response body as a string String body = given() .get("/session-info") .then() .extract() .body() .asString(); // Expected JSON string String expectedJson = "{\"activeSession\":true,\"token\":\"abc123\",\"details\":[{\"accountType\":2,\"accountDescription\":\"Premium\",\"username\":\"mr_fish\",\"clientId\":42}]}"; // Assert JSON, ignoring field order JSONAssert.assertEquals(expectedJson, body, JSONCompareMode.LENIENT); }
JSONAssert.assertEquals()
: This method allows for JSON comparisons that are tolerant of field order, preventing test failures due to differences in JSON key ordering.JSONCompareMode.LENIENT
: This mode ignores field order, comparing only the structure and values within the JSON data. This approach ensures that tests pass as long as all required fields and values are present, regardless of their order.
5. Asserting JSON with JSON Assert Hamcrest and JSON Unit Hamcrest
When dealing with JSON responses that contain dynamic or changeable fields, JSON Assert Hamcrest and JSONUnit Hamcrest provide effective ways to handle these variances while allowing the test to focus on expected fields and values. Both libraries can be used in combination with REST-assured for flexible assertions that ignore extra fields.
Adding Dependencies for JSON Assert Hamcrest and JSONUnit Hamcrest
To use JSON Assert Hamcrest and JSON Unit Hamcrest, the following dependencies should be added to the pom.xml
:
<dependency> <groupId>uk.co.datumedge</groupId> <artifactId>hamcrest-json</artifactId> <version>0.2</version> </dependency> <dependency> <groupId>net.javacrumbs.json-unit</groupId> <artifactId>json-unit</artifactId> <version>2.27.0</version> <scope>test</scope> </dependency>
5.1 Using JSON Assert Hamcrest
With JSON Assert Hamcrest, we can load an expected JSON structure from a file and assert it against the response while allowing extra fields in the JSON. Assuming we have an expected.json
file containing the expected JSON structure in the src/test/resources
directory. Here’s how to write a test using JSON Assert Hamcrest:
@Test void assertJsonWithExtraFields_JsonAssert() { given() .get("/session-info") .then() .body(sameJSONAs(Files.contentOf(new File("src/test/resources/expected.json"), StandardCharsets.UTF_8)) .allowingExtraUnexpectedFields()); }
In this example:
sameJSONAs
: Loads the expected JSON structure fromexpected.json
and compares it to the actual JSON response.allowingExtraUnexpectedFields()
: Ignores any additional fields in the actual JSON response, focusing on matching fields in the expected JSON.
5.2 Using JSONUnit Hamcrest
With JSONUnit Hamcrest, we can use options to make comparisons more flexible, such as ignoring extra fields or handling nested fields.
@Test void compareFieldsWithJsonUnitIgnoringExtras() { given() .get("/session-info") .then() .body(jsonEquals(Files.contentOf(new File("src/test/resources/expected.json"), StandardCharsets.UTF_8)) .when(Option.IGNORING_EXTRA_FIELDS)); }
In this example:
jsonEquals
: Compares the actual JSON response to the expected JSON structure loaded from the file.Option.IGNORING_EXTRA_FIELDS
: Ignores any additional fields not specified inexpected.json
, ensuring only relevant fields are validated.
6. Conclusion
In this article, the use of REST-assured for asserting JSON responses in Java has been explored, demonstrating several techniques for validating JSON structures effectively. By using REST-assured’s body()
and equalTo()
methods, along with additional tools like JSON Assert Hamcrest and JSON Unit Hamcrest, testers can achieve precise, flexible assertions that handle complex scenarios, including ignoring extra fields or comparing entire JSON bodies as strings.
7. Download the Source Code
This article focused on using Java REST-assured to assert JSON responses.
You can download the full source code of this example here: java rest assured assert json responses