Exploring the AssertJ Integration and New MockMvcTester Class in Spring Boot 3.4
Spring Boot 3.4 introduces AssertJ integration for tests and an exciting new class—MockMvcTester—designed to simplify and enhance testing of web controllers.
The AssertJ integration builds on top of plain MockMvc
with several differences:
- There is no need to use static imports as both the requests and assertions can be crafted using a fluent API.
- Unresolved exceptions are handled consistently so that your tests do not need to throw (or catch)
Exception
. - By default, the result to assert is complete whether the processing is asynchronous or not. In other words, there is no need for special handling for Async requests.
It offers a modern, fluent API for asserting HTTP responses, making it easier to write clean and readable tests.
In this blog post, we will explore the AssertJ Support and MockMvcTester class, its features, and how to use it with examples.
What is MockMvcTester?
MockMvcTester is a new API in Spring Boot 3.4 that simplifies integration testing of Spring MVC controllers. It builds on the existing MockMvc framework but adds:
- Fluent assertions for HTTP response properties.
- Seamless JSON handling with support for extracting and validating JSON path values.
- Improved readability with method chaining and expressive syntax.
Key Features:
- Fluent assertions for status codes, headers, and content types.
- JSON path extraction and validation.
- Easy integration with Java 8 streams and lambdas.
- Built-in support for HTTP methods and request setup.
Setup the Spring Boot Project
Go to start.spring.io and create a Spring Boot project by selecting version 3.4 or above
Create a Controller to Test
@RestController
@RequestMapping("/employee")
public class EmployeeController {
@Autowired
EmployeeService employeeService;
@GetMapping
public List<Employee> getEmployees() {
return employeeService.getAllEmployees();
}
@GetMapping(value="/{id}")
public Employee getEmployeeById(@PathVariable Integer id) {
return employeeService.getEmployeeById(id);
}
@PostMapping
public Employee createEmployee(@RequestBody Employee employee) {
return employeeService.createEmployee(employee);
}
@DeleteMapping(value="/{id}")
public void deleteEmployee(@PathVariable("id") Integer id){
employeeService.deleteEmployee(id);
}
}
Code language: Java (java)
Examples with MockMvcTester
Configuration
You could configure similar to MockMvc with @AutoConfigureMockMvc annotation
@SpringBootTest
@AutoConfigureMockMvc
public class EmpMockMvcTesterTest {
@Autowired private MockMvcTester mockMvc;
}
Code language: Java (java)
Below is another approach to configure MockMvcTester
@SpringBootTest
class EmployeeControllerTest {
private final MockMvcTester mockMvc;
@Autowired
EmployeeControllerTest(WebApplicationContext context) {
this.mockMvc = MockMvcTester.from(context);
}
}
Code language: Java (java)
Examples with MockMvcTester
1. Basic HTTP Assertions
@Test
public void testGetEmployeeById() {
MvcTestResult response = mockMvc.get().uri("/employee/100").exchange();
assertThat(response)
.hasStatusOk()
.hasContentTypeCompatibleWith(MediaType.APPLICATION_JSON_VALUE);
}
Code language: Java (java)
2. JSON Path Assertions
In below test I am using assertThatObject to verify the results. It saves you from type conversion of JsonPath reading.
@Test
public void testGetEmployeeById() throws UnsupportedEncodingException {
MvcTestResult response = mockMvc.get().uri("/employee/100").exchange();
assertThat(response)
.hasStatusOk()
.hasContentTypeCompatibleWith(MediaType.APPLICATION_JSON_VALUE);
var json = response.getResponse().getContentAsString();
assertThatObject(JsonPath.read(json, "first_name")).isEqualTo("Alex");
assertThatObject(JsonPath.read(json, "last_name")).isEqualTo("Bonilla");
assertThatObject(JsonPath.read(json, "department.name")).isEqualTo("HR");
}
Code language: Java (java)
If you want to use assertThat method to verify the results, you need to type cast the object like below.
assertThat((Integer) JsonPath.read(json, "id")).isEqualTo(100);
assertThat((String)JsonPath.read(json, "first_name")).isEqualTo("Alex");
assertThat((String)JsonPath.read(json, "last_name")).isEqualTo("Bonilla");
assertThat((String)JsonPath.read(json, "department.name")).isEqualTo("HR");
assertThat((String) JsonPath.read(json, "gender")).isEqualTo("M");
Code language: Java (java)
Here are few different ways you can assert the single object results.
assertThat(mockMvc.get().uri("/employee/100"))
.hasStatusOk()
.hasContentTypeCompatibleWith(MediaType.APPLICATION_JSON_VALUE)
.bodyJson()
.extractingPath("$")
.asMap()
.contains(entry("first_name", "Alex"), entry("last_name", "Bonilla"), entry("gender", "M"))
.containsKey("department")
.containsEntry("department", Map.of(
"id", 100,
"name", "HR"
));
Code language: Java (java)
assertThat(mockMvc.get().uri("/employee/100"))
.hasStatusOk()
.hasContentTypeCompatibleWith(MediaType.APPLICATION_JSON_VALUE)
.bodyJson()
.extractingPath("$")
.convertTo(Employee.class)
.satisfies(e -> assertThat(e.getFirst_name()).isEqualTo("Alex"))
.satisfies(e -> assertThat(e.getLast_name()).isEqualTo("Bonilla"));
Code language: Java (java)
Post Request examples
MvcTestResult response =
mockMvc
.post()
.uri("/employee")
.contentType(MediaType.APPLICATION_JSON)
.content(
"""
{
"first_name": "John",
"last_name": "Doe",
"gender": "M",
"birth_date": "1990-12-07",
"hire_date": "2011-04-01"
}
""")
.exchange();
assertThat(response.getResponse().getStatus()).isEqualTo(200);
assertThat(response.getResponse().getContentType()).isEqualTo(MediaType.APPLICATION_JSON_VALUE);
var json = response.getResponse().getContentAsString();
assertThatObject(JsonPath.read(json, "first_name")).isEqualTo("John");
assertThatObject(JsonPath.read(json, "last_name")).isEqualTo("Doe");
Code language: Java (java)
assertThat(
mockMvc
.post()
.uri("/employee")
.contentType(MediaType.APPLICATION_JSON)
.content(
"""
{
"first_name": "John",
"last_name": "Doe",
"gender": "M",
"birth_date": "1990-12-07",
"hire_date": "2011-04-01"
}
"""))
.hasStatusOk()
.hasContentTypeCompatibleWith(MediaType.APPLICATION_JSON_VALUE)
.bodyJson()
.extractingPath("$")
.asMap()
.contains(entry("first_name", "John"), entry("last_name", "Doe"), entry("gender", "M"));
Code language: Java (java)
assertThat(
mockMvc
.post()
.uri("/employee")
.contentType(MediaType.APPLICATION_JSON)
.content(
"""
{
"first_name": "John",
"last_name": "Doe",
"gender": "M",
"birth_date": "1990-12-07",
"hire_date": "2011-04-01"
}
"""))
.hasStatusOk()
.hasContentTypeCompatibleWith(MediaType.APPLICATION_JSON_VALUE)
.bodyJson()
.convertTo(Employee.class)
.satisfies(e -> assertThat(e.getFirst_name()).isEqualTo("John"))
.satisfies(e -> assertThat(e.getLast_name()).isEqualTo("Doe"));
Code language: Java (java)
4. Validating Lists and Counts
@Test
public void testGetEmployees() throws UnsupportedEncodingException {
MvcTestResult response = mockMvc.get().uri("/employee").exchange();
assertThat(response)
.hasStatusOk()
.hasContentTypeCompatibleWith(MediaType.APPLICATION_JSON_VALUE);
// Parse JSON response as String
var json = response.getResponse().getContentAsString();
// Verify count of objects
assertThat((Integer)JsonPath.read(json, "$.length()")).isEqualTo(8);
// Verify first object values
assertThatObject(JsonPath.read(json, "$[0].id")).isEqualTo(100);
assertThat((String) JsonPath.read(json, "$[0].first_name")).isEqualTo("Alex");
assertThat((String) JsonPath.read(json, "$[0].last_name")).isEqualTo("Bonilla");
assertThat((String) JsonPath.read(json, "$[0].department.name")).isEqualTo("HR");
// verify ids
List<Integer> empIds = JsonPath.read(json, "$[*].id");
assertThat(empIds).containsExactlyInAnyOrder(100, 200, 300, 400, 500, 600, 700, 800);
// verify first names
List<String> firstNames = JsonPath.read(json, "$[*].first_name");
assertThat(firstNames)
.containsExactlyInAnyOrder(
"Alex", "Duke", "Hayley", "Nancie", "Wyatt", "Tobey", "Marvin", "Ibrar");
}
Code language: Java (java)
If you want to chain assertions
assertThat(mockMvc.get().uri("/employee"))
.bodyJson()
.extractingPath("$")
.convertTo(InstanceOfAssertFactories.list(Employee.class))
.hasSize(8)
.satisfies(
e ->
assertThat(e.stream().map(Employee::getFirst_name).collect(Collectors.toList()))
.isEqualTo(
List.of(
"Alex", "Duke", "Hayley", "Nancie", "Wyatt", "Tobey", "Marvin",
"Ibrar")))
.satisfies(
e ->
assertThat(
e.stream().map(Employee::getDepartment).toList().stream()
.map(Department::getName)
.collect(Collectors.toList()))
.containsExactlyInAnyOrder(
"HR", "PDE", "Marketing", "HR", "PDE", "Marketing", "HR", "PDE"));
Code language: Java (java)
Using AssertJ With MockMvc Tests
You do not need use the MockMVcTester class in your tests to take advantages of AssertJ.
If you want to use the AssertJ support in MockMvc API, you can do that in following ways.
@SpringBootTest
@AutoConfigureMockMvc
public class EmpMockMvcAssertJTest {
@Autowired private MockMvc mockMvc;
@Test
public void testGetEmployeeById() throws Exception {
mockMvc
.perform(get("/employee/100"))
.andExpect(status().isOk())
.andExpect(
response -> {
var json = response.getResponse().getContentAsString();
assertThatObject(JsonPath.read(json, "first_name")).isEqualTo("Alex");
assertThatObject(JsonPath.read(json, "last_name")).isEqualTo("Bonilla");
assertThatObject(JsonPath.read(json, "department.name")).isEqualTo("HR");
assertThat((String) JsonPath.read(json, "gender")).isEqualTo("M");
});
}
}
Code language: Java (java)
@Test
public void testGetEmployeeById2() throws Exception {
assertThat(
mockMvc
.perform(get("/employee/100"))
.andExpect(status().isOk())
.andReturn()
.getResponse()
.getContentAsString())
.satisfies(
json -> {
assertThatObject(JsonPath.read(json, "first_name")).isEqualTo("Alex");
assertThatObject(JsonPath.read(json, "last_name")).isEqualTo("Bonilla");
assertThatObject(JsonPath.read(json, "department.name")).isEqualTo("HR");
assertThat((String) JsonPath.read(json, "gender")).isEqualTo("M");
});
}
Code language: Java (java)
@Test
public void testGetEmployees() throws Exception {
mockMvc
.perform(get("/employee"))
.andExpect(status().isOk())
.andExpect(
result -> {
var json = result.getResponse().getContentAsString();
List<Employee> employees = JsonPath.read(json, "$");
assertThat(employees).hasSize(8);
assertThat(employees)
.extracting("first_name")
.containsExactlyInAnyOrder(
"Alex", "Duke", "Hayley", "Nancie", "Wyatt", "Tobey", "Marvin", "Ibrar");
// assertThat(json)
int employeeCount = JsonPath.read(json, "$.length()");
assertThat(employeeCount).isEqualTo(8);
assertThatObject(JsonPath.read(json, "$[0].id")).isEqualTo(100);
// verify ids
List<Integer> empIds = JsonPath.read(json, "$[*].id");
assertThat(empIds).containsExactlyInAnyOrder(100, 200, 300, 400, 500, 600, 700, 800);
// verify first names
List<String> firstNames = JsonPath.read(json, "$[*].first_name");
assertThat(firstNames)
.containsExactlyInAnyOrder(
"Alex", "Duke", "Hayley", "Nancie", "Wyatt", "Tobey", "Marvin", "Ibrar");
});
}
Code language: Java (java)
Benefits of Using MockMvcTester
- Fluent API: The fluent API makes tests more readable and expressive.
- Reduced Boilerplate: Less code is required to set up and perform tests.
- Powerful Assertions: Built-in support for JSON Path, headers, and status codes.
- Seamless Integration: Works seamlessly with Spring Boot’s testing framework.
Conclusion
The MockMvcTester in Spring Boot 3.4 is a significant improvement for writing tests. It combines the best aspects of traditional MockMvc and modern fluent APIs like AssertJ, making it ideal for validating HTTP responses and JSON content in a clean, expressive manner.
Whether you’re starting a new project or updating existing tests, adopting MockMvcTester can streamline your testing strategy and improve code maintainability.
You can download the source code of blog post from GitHub