In this tutorial, we will explore how to write effective unit tests for REST controllers that return JSON responses. We will dive into using the JsonAssert library, which simplifies asserting JSON content by ignoring irrelevant differences such as spacing and order, and focusing only on the important fields.
Prerequisites
- A Spring Boot project with the
spring-boot-starter-test
dependency included in yourpom.xml
. - Basic knowledge of JUnit and unit testing REST controllers.
spring-boot-starter-test
brings in dependencies like JUnit, Mockito, Hamcrest, and importantly, JsonAssert—which we’ll use extensively.
What is JsonAssert?
JsonAssert is a powerful tool for asserting JSON content easily in unit tests. It allows flexible matching:
- Ignores extra spaces.
- You can specify only the fields you want to assert, ignoring other fields.
- Offers strict and non-strict modes for asserting JSON structure.
Understanding JsonAssert Under the Hood
When you use the .andExpect(content().json(expected))
method in Spring MockMvc tests:
- It internally calls
JsonAssert.assertEquals(expected, actual, strict)
withstrict
set tofalse
. - The actual JSON string comes from
response.getContentAsString()
. - The expected JSON string is whatever you pass in.
strict = false
means JsonAssert allows missing fields in the expected JSON and ignores order.
Basic Example
Let’s look at how to assert a JSON response using JsonAssert directly in a separate unit test spike class—independent of Spring MVC:
Step 1: Create a test class
package com.example.unit; import org.junit.jupiter.api.Test; import org.skyscreamer.jsonassert.JSONAssert; public class JsonAssertTest { @Test public void jsonAssertBasicTest() throws Exception { // Simulated JSON response from a service String actualResponse = "{ \"id\": 1, \"name\": \"Paul\", \"price\": 10, \"quantity\": 20 }"; // Expected JSON to match against (only asserting id, name, and price) String expectedResponse = "{ \"id\": 1, \"name\": \"Paul\", \"price\": 10 }"; // Perform the assertion ignoring extra fields (strict = false) JSONAssert.assertEquals(expectedResponse, actualResponse, false); } }
Explanation:
- The test passes, even though the
actualResponse
contains aquantity
field missing fromexpectedResponse
. - Because
strict
isfalse
, JsonAssert ignores any fields not present in the expected JSON.
Strict vs Non-Strict Mode
- strict=true : JSON must exactly match: all fields present, no extras. Spaces ignored.
- strict=false : Only compare fields in expected JSON; extras in actual are ignored.
Example for strict mode:
@Test public void jsonAssertStrictTest() throws Exception { String actualResponse = "{ \"id\": 1, \"name\": \"Paul\", \"price\": 10, \"quantity\": 20 }"; String expectedResponse = "{ \"id\": 1, \"name\": \"Paul\", \"price\": 10 }"; // This will fail because 'quantity' is missing from expected when strict=true JSONAssert.assertEquals(expectedResponse, actualResponse, true); }
When to use which mode?
- Use
strict=false
when you only care about validating some key fields. - Use
strict=true
when your exact JSON structure must match.
Handling Formatting and Escaping
- JsonAssert ignores spaces and formatting differences.
- You can write expected JSON without escape characters if values do not contain spaces or special characters.
Example:
String expected = "{ id:1, name:Paul, price:10 }"; // No quotes required around keys and simple values
If values contain spaces, escape with quotes:
String expected = "{ id:1, name:\"Paul Smith\", price:10 }";