skip to content

When would you use MOCK + MockMvc versus RANDOM_PORT + TestRestTemplate, and what does each actually exercise?

level: middleimportance: must knowfreq 68%

answer

  1. MockMvc = in-process DispatcherServlet, no socket
  2. TestRestTemplate = real HTTP over random port
  3. MockMvc rollback works; real-server rollback does NOT
  4. MOCK cheap+focused; RANDOM_PORT broad+realistic

basics

~10 s

Use 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 s

MockMvc (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
java
// 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

for a junior

Knows MockMvc is fast/in-process and TestRestTemplate hits a real server.

for a middle

Articulates what each actually exercises and picks the right tool per test.

for a senior

Balances a fast MockMvc suite with a few RANDOM_PORT smoke tests and handles data cleanup.

for a principal

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

context