When would you use MOCK + MockMvc versus RANDOM_PORT + TestRestTemplate, and what does each actually exercise?
answer
- MockMvc = in-process DispatcherServlet, no socket
- TestRestTemplate = real HTTP over random port
- MockMvc rollback works; real-server rollback does NOT
- MOCK cheap+focused; RANDOM_PORT broad+realistic
basics
~10 sUse MOCK + MockMvc for fast in-process controller tests that never touch the network. Use RANDOM_PORT + TestRestTemplate when you need a real embedded server and real HTTP requests to test the full stack.
solid answer
~40 sMockMvc (under WebEnvironment.MOCK) dispatches requests directly through the DispatcherServlet in the same JVM thread — no socket, no real connector. It's fast and ideal for verifying the MVC layer: routing, `@ControllerAdvice`, argument resolvers, validation, status/JSON output. It cannot see anything that only happens on a real server. RANDOM_PORT starts the actual embedded container and TestRestTemplate makes genuine HTTP calls over loopback, so it exercises the full stack: real connectors, HTTP message conversion end-to-end, filters, and integration with external HTTP clients. Cost: it's slower and, because the server runs on its own thread, `@Transactional` rollback on the test doesn't undo server-side writes. Rule of thumb: default to MockMvc for controller behavior; reach for RANDOM_PORT/TestRestTemplate (or WebTestClient) for true end-to-end HTTP tests or when you must validate the deployed transport.
code
java · 15 lines// Real HTTP end-to-end with relative URL resolution
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class EndToEndTest {
@Autowired TestRestTemplate rest; // knows the random port
@Test
void createReturns201() {
var resp = rest.postForEntity("/api/users",
new UserDto("ada"),
Void.class);
assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.CREATED);
// NOTE: this write is committed by the server thread;
// a @Transactional test would NOT roll it back.
}
}go deeper
Knows MockMvc is fast/in-process and TestRestTemplate hits a real server.
Articulates what each actually exercises and picks the right tool per test.
Balances a fast MockMvc suite with a few RANDOM_PORT smoke tests and handles data cleanup.
Frames it as a cost/realism trade-off and sets team conventions (default MockMvc, targeted end-to-end).
## The two testing styles ### MOCK + `MockMvc` - Enabled by `@SpringBootTest` (default `WebEnvironment.MOCK`) plus `@AutoConfigureMockMvc`, or by the slice annotation `@WebMvcTest` (which loads only the web layer). - `MockMvc` builds requests with `MockHttpServletRequest` and pushes them **through the real `DispatcherServlet` in-process**. There is **no TCP socket and no embedded server**. - **What it exercises:** URL mapping (`@GetMapping` etc.), path/query/body binding, `@Valid` validation, `HandlerInterceptor`s, `@ControllerAdvice` exception handling, view/JSON serialization via `HttpMessageConverter`s, response status and headers. - **What it does NOT exercise:** the real servlet container, real connectors, actual socket I/O, servlet `Filter`s that Boot registers with the container (unless you wire them into MockMvc), or genuine HTTP-client interop. - **Pros:** very fast (no networking), deterministic, runs on the test thread (so `@Transactional` rollback works normally). **Cons:** it's a simulation of HTTP, not the real thing. ### RANDOM_PORT/DEFINED_PORT + `TestRestTemplate` (or `WebTestClient`) - `@SpringBootTest(webEnvironment = RANDOM_PORT)` starts the **real embedded container** on a random free port. - `TestRestTemplate` is auto-configured and, being aware of `@LocalServerPort`, lets you use **relative URLs** (`/hello`) — it resolves them against the running port. `WebTestClient` (reactive fluent client) works similarly and can also bind to a MockMvc/handler when configured. - **What it exercises:** the **entire stack end-to-end** — real Tomcat/Jetty, real connectors, the full filter chain as deployed, HTTP message conversion on both ends, and behavior of a real HTTP client. This is the closest to production. - **Cons:** slower; the **server runs on a separate thread** from the test, so a `@Transactional` test method **cannot roll back** what the server committed — you must clean up data yourself (e.g. `@Sql`, delete in `@AfterEach`, or `@DirtiesContext`). Real ports also mean flakiness risk if you (wrongly) use DEFINED_PORT. ## Decision guide - Testing **controller logic / MVC concerns** → MockMvc (MOCK). Cheapest, fastest, most focused. - Testing the **real HTTP contract**, servlet-container behavior, or an end-to-end path a client will actually take → RANDOM_PORT + TestRestTemplate/WebTestClient. - Need **both fast and broad**? Keep the bulk of controller tests on MockMvc and add a small number of RANDOM_PORT smoke tests for critical paths. ## Common mistakes - Using `TestRestTemplate` under MOCK (it isn't configured; nothing is listening). - Expecting a `@Transactional` test to undo writes made through a real HTTP call under RANDOM_PORT. - Assuming MockMvc runs your Boot-registered servlet filters exactly as production does (it may not, unless added to the MockMvc setup).
- Can MockMvc test a servlet Filter?Only if the filter is added to the MockMvc setup (e.g. via MockMvcBuilders...addFilter or Spring Boot's auto-config that wires security filters). MockMvc does not automatically run every container-registered filter the way a real embedded server does under RANDOM_PORT.
- How does TestRestTemplate know which port to hit?Under RANDOM_PORT it's auto-configured with the actual local server port (the same value @LocalServerPort injects), so you can pass relative paths like /api/users and it prefixes http://localhost:<port>.
saying these in an interview costs you the question
- Claiming MockMvc makes real network calls
- Using TestRestTemplate under MOCK
- Expecting @Transactional to roll back server writes in RANDOM_PORT