skip to content

Endpoint Testing & Assertions

Actually asserting on endpoints: MockMvc and its AssertJ successor, WebTestClient, JSON assertions, result handlers, REST Docs, security test support and TestRestTemplate. This is where most day-to-day Spring test code is written.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

explore

questions

page 2 of 2

Compare @WithMockUser, @WithUserDetails, and @WithSecurityContext. When do you need each?

level: seniorimportance: should knowfreq 55%

basics

~20 s

@WithMockUser fabricates a simple principal from annotation attributes. @WithUserDetails loads a real principal via your UserDetailsService bean by username, so the principal is your actual UserDetails type. @WithSecurityContext is the extensible base that lets you build a fully custom SecurityContext/Authentication via a factory.

open as a page

Beyond jsonPath, what body-assertion and result-extraction options does WebTestClient offer, and when would you use expectBody(Class) vs expectBodyList vs returnResult?

level: seniorimportance: should knowfreq 45%

basics

~20 s

expectBody(Class) decodes one object; expectBodyList(Class) decodes an array to a List; expectBody() (untyped) gives jsonPath/json(...) assertions on raw JSON; returnResult(Class) exits the fluent chain to get the decoded body (a Flux for streaming) for custom assertions.

open as a page

When do you use andReturn/MvcResult, how do you test async controller methods, and what are MockMvc's fundamental limitations?

level: principalimportance: should knowfreq 35%

basics

~20 s

andReturn() gives you the MvcResult for custom assertions on the raw response. For async endpoints (returning DeferredResult/Callable/CompletableFuture), first andExpect(request().asyncStarted()), then re-dispatch with asyncDispatch(mvcResult). MockMvc's key limit: it runs the DispatcherServlet in-memory, not a real HTTP server.

open as a page

At scale, how do you keep Spring REST Docs maintainable — reducing per-test boilerplate, keeping constraints/docs in sync, and what tradeoffs does the test-driven-docs approach carry?

level: principalimportance: should knowfreq 22%

basics

~20 s

Centralize preprocessors and URI config as defaults, extract reusable snippet/descriptor helpers, drive validation docs from Bean Validation via ConstraintDescriptions, and use snippet templates for consistency. The tradeoff: docs require and depend on maintained tests, and drift breaks the build (intentionally).

open as a page

A team's MockMvc POST tests intermittently fail with 403 despite @WithMockUser, and their 'anonymous access returns 401' test passes even after they broke config. What test-support pitfalls explain this?

level: principalimportance: should knowfreq 35%

basics

~20 s

The 403 comes from missing CSRF tokens on mutating requests — @WithMockUser authenticates but doesn't add one; they must use .with(csrf()). The false-passing test likely tests without wiring Spring Security into MockMvc (no apply(springSecurity())) or a @WebMvcTest with mocked/absent filter chain, so security isn't actually enforced.

open as a page

When would you choose TestRestTemplate versus WebTestClient (and how does MockMvc fit) for testing web endpoints?

level: principalimportance: should knowfreq 45%

basics

~20 s

Use TestRestTemplate for blocking, real-HTTP integration tests in a classic MVC app — simple, imperative, RestTemplate-style API. Use WebTestClient for its fluent assertion DSL, for reactive/WebFlux apps, or when you want one client that can bind to a live server, MockMvc, or controllers. MockMvc tests the MVC stack without a real socket.

open as a page

What are the subtle traps with JSONPath number typing, and the difference between `exists`/`doesNotExist`/`isEmpty`/`isNotEmpty`?

level: principalimportance: nice to knowfreq 30%

basics

~20 s

JsonPath maps small JSON integers to Integer and decimals to Double, so .value(1L) fails against 1. exists/doesNotExist test key presence; isEmpty/isNotEmpty test whether a present value is null/empty vs populated. A present-but-null field exists AND isEmpty.

open as a page

Explain MockMvcTester's lazy exchange model and when you'd adopt it versus classic MockMvc or WebTestClient.

level: principalimportance: nice to knowfreq 25%

basics

~20 s

The request builder is an AssertJ AssertProvider, so the request only runs when you call assertThat(...) or .exchange(). Adopt MockMvcTester for readable AssertJ servlet-slice tests; keep classic MockMvc where it's already entrenched; use WebTestClient for real-HTTP/WebFlux or full-stack tests.

open as a page

How would you standardize MockMvc debugging and security across a large test suite using result handlers, `alwaysDo`, and `apply(springSecurity())` — and what are the trade-offs?

level: principalimportance: nice to knowfreq 20%

basics

~10 s

Build a shared MockMvc via a base class or MockMvcBuilderCustomizer: apply(springSecurity()) for security plus alwaysDo(log()) for uniform, DEBUG-gated diagnostics. Keep global alwaysExpect minimal and add custom ResultHandlers only for cross-cutting captures.

open as a page

As a tech lead, how do you decide between mock-server and running-server WebTestClient tests, and what pitfalls (timeouts, fidelity, security) do you watch for?

level: principalimportance: nice to knowfreq 25%

basics

~10 s

Use fast mock-server tests (bindToController/context, webEnvironment MOCK) for most controller coverage; reserve slower running-server tests (RANDOM_PORT) for transport, filter-ordering, and true end-to-end concerns. Watch response timeouts, hidden config gaps, and security-context wiring.

open as a page

showing 31–40 of 40