What is MockMvcTester in Spring 6.2, and how do you use it to assert a controller returns 200 with a JSON body?
answer
- Spring 6.2 fluent AssertJ over MockMvc
- assertThat(mvc.get().uri(...)).hasStatusOk()
- create(mockMvc) / from(context) / of(controllers)
- bodyJson().extractingPath("$.x")
- still mock servlet stack, no real server
basics
~10 sMockMvcTester (Spring 6.2) is a fluent, AssertJ-based wrapper around MockMvc. You perform a request like mvc.get().uri("/x") and pass it to AssertJ's assertThat(...), then chain checks such as .hasStatusOk() and .bodyJson().
solid answer
~40 sMockMvcTester, added in Spring Framework 6.2, is a fluent facade over MockMvc that integrates with AssertJ instead of MockMvc's older Hamcrest-style ResultMatchers. You build a request with a fluent builder (mvc.get().uri("/users/1")), wrap it in AssertJ's assertThat(...), and chain readable assertions: .hasStatusOk(), .hasContentType(MediaType.APPLICATION_JSON), and .bodyJson() to assert JSON content via JSONPath. It still drives the same mock servlet stack (DispatcherServlet) as classic MockMvc — no real HTTP or running server. You create it with MockMvcTester.create(existingMockMvc) or MockMvcTester.from(webApplicationContext). Under Spring Boot 3.4+, a MockMvcTester bean is auto-configured with @WebMvcTest / @AutoConfigureMockMvc, so you can inject it directly. It gives more readable failures and better IDE completion than perform(...).andExpect(...).
code
java · 17 linesimport static org.assertj.core.api.Assertions.assertThat;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
class UserControllerTests {
private final MockMvcTester mvc; // e.g. MockMvcTester.create(mockMvc) or injected
UserControllerTests(MockMvcTester mvc) { this.mvc = mvc; }
void returnsUser() {
assertThat(mvc.get().uri("/users/{id}", 1))
.hasStatusOk()
.hasContentType(MediaType.APPLICATION_JSON)
.bodyJson()
.extractingPath("$.name").isEqualTo("Alice");
}
}go deeper
Know it's the new fluent AssertJ way to test controllers; recognize assertThat(mvc.get().uri(...)).hasStatusOk().
Know the create/from/of factories and the main body/status/header assertions, plus Boot 3.4 auto-config.
Contrast with classic MockMvc, explain lazy exchange, exception capture, and JSON assertions.
Advise on adoption strategy, migration from perform(...), and where MockMvcTester fits vs WebTestClient in a testing pyramid.
## What it is **MockMvcTester** is a class introduced in **Spring Framework 6.2** that provides a **fluent, AssertJ-flavored** API on top of the existing **MockMvc** testing infrastructure. MockMvc lets you test Spring MVC controllers without starting a real web server: it wires up the `DispatcherServlet` and processes mock `HttpServletRequest`/`HttpServletResponse` objects in-process. The classic MockMvc API reads like `mockMvc.perform(get("/x")).andExpect(status().isOk())` and uses Hamcrest `Matcher`s. MockMvcTester keeps the same underlying engine but exposes it through **AssertJ**, the fluent assertion library (`assertThat(...).hasXxx()`), which most teams already use. ## Creating it - `MockMvcTester.create(MockMvc mockMvc)` — wrap an existing `MockMvc` instance you already built. - `MockMvcTester.from(WebApplicationContext context)` — build from the full web application context (optionally passing a customizer to tweak the underlying builder). - `MockMvcTester.of(controllers...)` — a **standalone** setup that registers only the given controller instances (no full context), analogous to `MockMvcBuilders.standaloneSetup(...)`. - Under **Spring Boot 3.4+**, `@WebMvcTest` and `@AutoConfigureMockMvc` auto-configure a `MockMvcTester` bean, so you just `@Autowired MockMvcTester mvc`. ## Performing a request You start with an HTTP-method builder: `mvc.get()`, `mvc.post()`, `mvc.put()`, `mvc.delete()`, or `mvc.method(HttpMethod.PATCH)`. You then configure it fluently: `.uri("/users/{id}", 1)`, `.param("q", "spring")`, `.contentType(MediaType.APPLICATION_JSON)`, `.content(json)`, `.accept(...)`, `.header(...)`, `.cookie(...)`. The resulting builder is special: it implements AssertJ's `AssertProvider`, so passing it to `assertThat(...)` **triggers the request lazily** and returns an `MvcTestResultAssert`. You can also call `.exchange()` explicitly to get an `MvcTestResult` and assert on it later. ## Common assertions - **Status:** `.hasStatusOk()`, `.hasStatus(HttpStatus.CREATED)`, `.hasStatus(201)`, `.hasStatus2xxSuccessful()`, `.hasStatus4xxClientError()`. - **Headers / content type:** `.hasContentType(MediaType.APPLICATION_JSON)`, `.headers().hasValue("X-Trace", "...")`. - **Body as text:** `.body().asString().contains("...")` (or `.hasBodyTextEqualTo(...)`). - **Body as JSON:** `.bodyJson()` returns a JSON assert you can drive with JSONPath: `.extractingPath("$.name").isEqualTo("Alice")`, `.hasPathSatisfying("$.id", v -> v.assertThat().isNotNull())`, or compare whole documents with `.isLenientlyEqualTo(...)` / `.isStrictlyEqualTo(...)`. - **Redirects / views (for server-rendered MVC):** `.hasRedirectedUrl(...)`, `.hasForwardedUrl(...)`, `.hasViewName(...)`, `.model()`. ## Why use it - **Readability + IDE completion:** AssertJ chains discover methods via autocomplete; failure messages are richer than Hamcrest. - **Consistency:** if your project already asserts with AssertJ, tests read uniformly. - **Exception capture:** unlike classic MockMvc (which rethrows an unresolved handler exception out of `perform`), MockMvcTester captures it so you can assert on the failure (`.hasFailed()`, `.failure()`). ## Gotchas - It is **not** a real HTTP client — still the mock servlet stack; use `WebTestClient` or `TestRestClient`/`RestAssured` against a running server for full-stack tests. - `.bodyJson()` needs a JSONPath/JSON library on the classpath (present via spring-test / Spring Boot test starter). - The request runs **lazily** on `assertThat(...)` or `.exchange()`; forgetting to assert means the request never executes.
- Does MockMvcTester start a real HTTP server?No. It drives the same in-memory mock servlet stack (DispatcherServlet) as classic MockMvc — no socket, no running server. For real HTTP use WebTestClient or a client against a @SpringBootTest(webEnvironment=RANDOM_PORT) server.
- How does it differ from mockMvc.perform(...).andExpect(...)?Same engine, different assertion style: MockMvcTester uses fluent AssertJ (assertThat(...).hasStatusOk()) instead of Hamcrest ResultMatchers, giving better IDE completion, richer failure messages, and the ability to capture and assert on unresolved exceptions.
saying these in an interview costs you the question
- Thinking MockMvcTester makes real HTTP calls / starts a server
- Confusing it with WebTestClient (reactive/real-HTTP)
- Claiming it still uses Hamcrest matchers