How does WebTestClient compare to MockMvc for testing Spring MVC endpoints, and how do you configure WebTestClient in a Spring Boot test?
answer
- MockMvc = MVC-only, servlet mock, perform/andExpect
- WebTestClient = MVC + WebFlux, mock or real server, fluent
- @AutoConfigureWebTestClient + @Autowired
- MOCK → mock server; RANDOM_PORT → real server
- @WebFluxTest auto-provides it
basics
~10 sBoth test controllers. MockMvc is MVC-only with a servlet-style API; WebTestClient is a fluent client that works for WebFlux and MVC, real or mock server. In Boot, add @AutoConfigureWebTestClient (or @WebFluxTest) and inject WebTestClient.
solid answer
~50 sMockMvc is the classic Spring MVC test tool: it drives the DispatcherServlet through a mock request/response without a real socket, with a perform/andExpect API. WebTestClient is a newer fluent HTTP client that tests both WebFlux and MVC and can run against a mock server or a real running server, giving one consistent API across stacks. For MVC it can even wrap MockMvc under the hood (bindToApplicationContext / Boot's mock environment). Configuration in Boot: for a full-context test use @SpringBootTest plus @AutoConfigureWebTestClient and @Autowired WebTestClient — MOCK environment gives a mock-server client, RANDOM_PORT gives a server-bound one. For reactive slices, @WebFluxTest auto-provides a WebTestClient. Prefer WebTestClient for new reactive code and when you want the same fluent style everywhere; MockMvc remains fine and widely used for pure MVC. You customize timeouts, base URL, default headers, and codecs via mutate()/builder.
code
java · 16 lines@WebFluxTest(UserController.class)
class UserControllerTest {
@Autowired WebTestClient client;
@MockBean UserService service;
@Test
void returnsUser() {
given(service.find(1L)).willReturn(Mono.just(new User(1L, "Ada")));
client.get().uri("/users/1")
.exchange()
.expectStatus().isOk()
.expectBody().jsonPath("$.name").isEqualTo("Ada");
}
}go deeper
Know both test controllers and that WebTestClient uses a fluent exchange() API.
Explain the MVC-only vs both-stacks distinction and the Boot annotations to wire WebTestClient.
Map webEnvironment values to mock vs real server and know WebTestClient can wrap MockMvc for MVC.
Set a team standard on MockMvc vs WebTestClient and where real-HTTP fidelity is required.
## Two tools, overlapping jobs ### MockMvc (`org.springframework.test.web.servlet.MockMvc`) - **Spring MVC only** (servlet stack). Simulates the `DispatcherServlet` with `MockHttpServletRequest`/`Response` — **no real socket**. - API style: `mockMvc.perform(get("/users/1")).andExpect(status().isOk()).andExpect(jsonPath("$.name").value("Ada"))`. - Set up via `@WebMvcTest` (slice), `MockMvcBuilders.standaloneSetup(controller)`, or `webAppContextSetup(context)`. ### WebTestClient - Works for **both WebFlux and Spring MVC**, against a **mock server or a real running server**. - Fluent API: `client.get().uri("/users/1").exchange().expectStatus().isOk().expectBody().jsonPath("$.name").isEqualTo("Ada")`. - For MVC in a mock environment it delegates to MockMvc-style infrastructure; for a real server it makes genuine HTTP calls. ## Why WebTestClient exists / when to prefer it - **Uniform API across stacks** — same test style whether the app is MVC or WebFlux, mock or real. - **Reactive-aware** — handles `Mono`/`Flux`, SSE, `StepVerifier` extraction via `returnResult`. - **End-to-end capable** — `bindToServer` hits a real embedded server, which MockMvc cannot do. MockMvc is still perfectly valid and extremely common for MVC apps; many teams keep it. WebTestClient is the recommended default for WebFlux and a good choice when you want one consistent client and/or real-HTTP tests. ## Configuring WebTestClient in Spring Boot ### Full-context test ```java @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @AutoConfigureWebTestClient class UserApiTest { @Autowired WebTestClient client; // server-bound at the random port } ``` - `webEnvironment = MOCK` (default) + `@AutoConfigureWebTestClient` → **mock-server** client bound to the context (for MVC it's built on MockMvc). - `webEnvironment = RANDOM_PORT`/`DEFINED_PORT` → **server-bound** client over real HTTP. ### Reactive slice ```java @WebFluxTest(UserController.class) class UserControllerTest { @Autowired WebTestClient client; // auto-provided, mock server @MockBean UserService service; } ``` `@WebFluxTest` is the WebFlux analogue of `@WebMvcTest` and wires a WebTestClient automatically. ### Customization via mutate()/builder ```java WebTestClient customized = client.mutate() .responseTimeout(Duration.ofSeconds(10)) .defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer token") .build(); ``` You can also set `baseUrl`, default cookies, codecs, and apply `WebTestClientConfigurer`s (e.g. Spring Security Test's `mockUser`). ## Gotchas - With `webEnvironment = MOCK`, there's **no real port**, so filters that depend on the servlet container transport may behave slightly differently than a running server; for genuine transport fidelity use `RANDOM_PORT`. - `@WebFluxTest` will not load MVC controllers, and `@WebMvcTest` won't wire a WebTestClient by default — match the slice to the stack. - WebTestClient over MVC-mock still exercises Spring's serialization and mapping, but not the real embedded container. - Default response timeout (5s) applies; slow integration tests may need `mutate().responseTimeout(...)`. - Spring Security tests: use `.mutateWith(mockUser())`/`csrf()` from `spring-security-test`, not manual header hacking.
- Can WebTestClient make real network calls, and can MockMvc?WebTestClient can via bindToServer / @SpringBootTest(RANDOM_PORT). MockMvc cannot — it only simulates the DispatcherServlet with mock request/response, no socket.
- Which annotation auto-provides a WebTestClient for a reactive controller slice test?@WebFluxTest — the WebFlux analogue of @WebMvcTest — wires a mock-server WebTestClient automatically.
saying these in an interview costs you the question
- Saying MockMvc can test WebFlux controllers or make real HTTP calls.
- Claiming WebTestClient cannot test Spring MVC.
- Forgetting @AutoConfigureWebTestClient when injecting WebTestClient in a @SpringBootTest.