What is MockMvc and how do you write a basic controller test with perform and andExpect?
answer
- No socket — DispatcherServlet in-memory
- perform(get(...)).andExpect(status().isOk())
- RequestBuilders / perform / ResultMatchers
- andDo(print()), andReturn() -> MvcResult
- @WebMvcTest gives you a MockMvc
basics
~10 sMockMvc lets you test Spring MVC controllers without starting a real HTTP server. You call mockMvc.perform(get("/url")) to send a fake request, then chain andExpect(status().isOk()) to assert on the response.
solid answer
~30 sMockMvc is Spring's server-side test harness for MVC controllers. It runs the full DispatcherServlet flow (mapping, argument resolution, the controller method, message converters, exception handling) in-process, with no socket or real servlet container, so it's fast and deterministic. You build requests with MockMvcRequestBuilders (get, post, put, delete, multipart), execute them via mockMvc.perform(...), and assert with MockMvcResultMatchers chained through andExpect — status().isOk(), content().json(...), jsonPath(...), header(...). andDo(print()) dumps the request/response for debugging, and andReturn() hands back the MvcResult for custom assertions. You obtain a MockMvc from @WebMvcTest (auto-configured, sliced) or build one manually with MockMvcBuilders.standaloneSetup / webAppContextSetup.
code
java · 19 lines@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired MockMvc mockMvc;
@MockitoBean UserService userService;
@Test
void returnsUser() throws Exception {
when(userService.find(42L)).thenReturn(new User(42L, "Ada"));
mockMvc.perform(get("/users/{id}", 42))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.name").value("Ada"));
}
}
// static imports: MockMvcRequestBuilders.get,
// MockMvcResultMatchers.*, MockMvcResultHandlers.printgo deeper
Must know perform + andExpect(status().isOk()) and that no server starts.
Should wire it via @WebMvcTest, mock collaborators, assert JSON with jsonPath.
Explains the full DispatcherServlet pipeline runs in-memory and where filters fit.
Frames MockMvc vs WebTestClient/TestRestTemplate trade-offs across the test pyramid.
**MockMvc** is the core class in Spring's `spring-test` module for testing Spring MVC (web) controllers *without a running servlet container* (no Tomcat, no TCP socket, no real network). Instead it drives a `MockHttpServletRequest`/`MockHttpServletResponse` pair through the actual `DispatcherServlet`, so the full server-side request-processing pipeline runs in-memory: handler mapping (which `@RequestMapping`/`@GetMapping` method matches), argument resolution (`@RequestParam`, `@PathVariable`, `@RequestBody` via `HttpMessageConverter`), the controller invocation, return-value handling, `@ExceptionHandler`/`@ControllerAdvice`, and view/serialization. Because there is no socket, tests are fast and deterministic, but you are testing the *Spring MVC layer*, not real HTTP. **The three moving parts:** 1. **`MockMvcRequestBuilders`** — static factory for requests: `get(uri)`, `post(uri)`, `put`, `delete`, `patch`, `multipart(uri)`. You fluently add `.param(...)`, `.header(...)`, `.contentType(MediaType.APPLICATION_JSON)`, `.content(jsonString)`, `.accept(...)`, `.cookie(...)`. Typically static-imported. 2. **`mockMvc.perform(RequestBuilder)`** — executes the request and returns a `ResultActions`. 3. **`MockMvcResultMatchers`** — static factory for assertions: `status()`, `content()`, `header()`, `jsonPath(...)`, `redirectedUrl(...)`, `view()`, `model()`. Each `andExpect(matcher)` verifies one thing; failures throw `AssertionError`. **A minimal test flow:** ```java mockMvc.perform(get("/users/42")) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.name").value("Ada")); ``` **Obtaining a MockMvc instance** — three routes: - **`@WebMvcTest(MyController.class)`** auto-configures a sliced MockMvc (only the web layer; you mock collaborators with `@MockitoBean`). - **`MockMvcBuilders.webAppContextSetup(wac)`** builds one from a full `WebApplicationContext` (usually with `@SpringBootTest` + `@AutoConfigureMockMvc`, or `@WebMvcTest` does this under the hood). - **`MockMvcBuilders.standaloneSetup(controllerInstance)`** registers controllers manually with no Spring context. **Chaining helpers:** `andDo(print())` (from `MockMvcResultHandlers`) prints the full request/response — invaluable when an assertion fails. `andReturn()` returns the `MvcResult` so you can pull `getResponse().getContentAsString()` for custom parsing. **Gotchas:** MockMvc does not run a real container, so servlet filters run only if explicitly registered (`.addFilters(...)` in standalone; auto-added under `@WebMvcTest`/`@AutoConfigureMockMvc`). It does not test actual HTTP semantics, connection handling, or real deserialization at the socket level — for that use `WebTestClient` or `TestRestTemplate` with `@SpringBootTest(webEnvironment=RANDOM_PORT)`. Assertions stop at the first failing `andExpect` unless you use `andExpectAll(...)`.
- Does MockMvc start a real HTTP server or open a port?No. It drives the DispatcherServlet in-process using mock request/response objects. There is no socket. For real HTTP use TestRestTemplate or WebTestClient with a RANDOM_PORT @SpringBootTest.
- Why does perform throw a checked Exception?perform(...) declares throws Exception, so JUnit test methods typically declare throws Exception too. It surfaces any exception from the dispatch pipeline that wasn't handled.