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 1 of 2

In a MockMvc test, how do you assert that a JSON response body has a field `name` equal to "Ada"?

level: juniorimportance: must knowfreq 80%

answer

  1. $ = root, dot navigates
  2. jsonPath from MockMvcResultMatchers
  3. returns JsonPathResultMatchers
  4. .value() / .exists() / .isArray()
  5. chain inside andExpect

basics

~10 s

Use .andExpect(jsonPath("$.name").value("Ada")), statically importing jsonPath from MockMvcResultMatchers. $ is the JSON root and .name navigates to the field.

solid answer

~30 s

After performing the request you chain `.andExpect(jsonPath("$.name").value("Ada"))`. `jsonPath` is a static method on `org.springframework.test.web.servlet.result.MockMvcResultMatchers` that returns a `JsonPathResultMatchers`; `$` denotes the JSON document root and `$.name` is the JSONPath expression selecting the top-level `name` property. `.value(...)` asserts the extracted value equals the expected object. You can layer more expectations on the same `andExpect` chain — `jsonPath("$.id").exists()`, `jsonPath("$.age").value(36)`, etc. This only works when the response `Content-Type` is JSON so the path evaluator can parse the body. It's the standard, readable way to assert on individual fields without deserializing the whole payload into a DTO.

code

java · 11 lines
java
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@Test
void returnsUser() throws Exception {
    mockMvc.perform(get("/users/1"))
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.name").value("Ada"))
        .andExpect(jsonPath("$.age").value(36))
        .andExpect(jsonPath("$.email").exists());
}

go deeper

for a junior

Know $ is root, jsonPath("$.field").value(...) is the core assertion, and it lives on MockMvcResultMatchers.

for a middle

Should also reach for .exists(), .isArray(), and Hamcrest matcher overloads.

for a senior

Explains number-typing gotcha and null-vs-absent distinction without prompting.

for a principal

Frames jsonPath as field-level assertion vs whole-document compare and sets team conventions for readability.

**What JSONPath is:** JSONPath is a query language for JSON, analogous to XPath for XML. An expression starts at the document **root**, written `$`. `$.name` selects the `name` property of the root object; `$.address.city` navigates nested objects; `$.items[0]` indexes into an array; `$.items[*].id` selects the `id` of every array element. Spring uses the **Jayway JsonPath** library under the hood to evaluate these expressions against the response body. **Where the matcher comes from:** In MockMvc you statically import `jsonPath` from `org.springframework.test.web.servlet.result.MockMvcResultMatchers` (or its aggregator `MockMvcResultMatchers.jsonPath(...)`). It returns a `JsonPathResultMatchers` object exposing assertion methods: - `.value(Object)` — the selected value equals the expected value. - `.value(Matcher<T>)` — the value satisfies a Hamcrest matcher (e.g. `greaterThan(10)`). - `.exists()` / `.doesNotExist()` — the path resolves / does not resolve. - `.isEmpty()` / `.isNotEmpty()` — the value is empty/absent vs present and non-empty. - `.isArray()`, `.isMap()`, `.isString()`, `.isNumber()`, `.isBoolean()` — type assertions. **How it plugs in:** `mockMvc.perform(get("/users/1")).andExpect(status().isOk()).andExpect(jsonPath("$.name").value("Ada"))`. Each `andExpect` takes a `ResultMatcher`; `jsonPath(...).value(...)` produces one. Assertions are evaluated against the recorded `MockHttpServletResponse` body. **Gotchas:** - The response must actually be JSON; if the endpoint returns an error HTML page or empty body the path evaluation throws and the test fails with a parse error, not a clean mismatch. - Number typing: JsonPath deserializes small integers to `Integer`. `.value(36)` works; `.value(36L)` fails because `Long` ≠ `Integer`. Prefer Hamcrest `is(36)` or match the exact type. - `$` is required — a bare `name` is not a valid root-relative expression here. - `.value(null)` asserts the field is JSON `null` (present but null), which differs from `.doesNotExist()` (absent key). **When to use:** Use `jsonPath` for targeted, field-level assertions that stay readable and don't require you to deserialize the whole body. For full-document equality, prefer `content().json(...)` instead.

  • What is the difference between `jsonPath("$.email").doesNotExist()` and `jsonPath("$.email").isEmpty()`?
    `doesNotExist()` passes when the key is absent from the JSON. `isEmpty()` passes when the key is present but its value is null or an empty string/array/collection. A present-but-null field satisfies `isEmpty()` but fails `doesNotExist()`.
  • Why might `jsonPath("$.id").value(1L)` fail even though the response id is 1?
    JsonPath deserializes the small integer to `Integer`, and `.value(1L)` compares against a `Long`, so equality fails on type. Use `.value(1)` or `jsonPath("$.id").value(is(1))`.

saying these in an interview costs you the question

  • Thinking you must deserialize the whole body into a DTO to assert one field
  • Writing the path without the `$` root
  • Believing `.value(null)` and `.doesNotExist()` mean the same thing

context

open as a page

What is MockMvcTester in Spring 6.2, and how do you use it to assert a controller returns 200 with a JSON body?

level: juniorimportance: must knowfreq 70%

basics

~10 s

MockMvcTester (Spring 6.2) is a fluent, AssertJ-based wrapper around MockMvc. You perform a request like mvc.get().uri("/x") and pass it to AssertJ's assertThat(...), then chain checks such as .hasStatusOk() and .bodyJson().

open as a page

What is MockMvc and how do you write a basic controller test with perform and andExpect?

level: juniorimportance: must knowfreq 80%

basics

~10 s

MockMvc 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.

open as a page

What is Spring REST Docs, and how do you enable it and produce a documentation snippet from a MockMvc test?

level: juniorimportance: must knowfreq 55%

basics

~10 s

Spring REST Docs generates API documentation from passing tests. You add @AutoConfigureRestDocs to a @WebMvcTest, then call MockMvc's perform(...).andDo(document("identifier")) to capture the request and response as reusable snippets.

open as a page

In a MockMvc test, what does `.andDo(MockMvcResultHandlers.print())` do, and when would you use it?

level: juniorimportance: must knowfreq 62%

basics

~10 s

It prints the full request and response (URL, headers, status, body, handler) to System.out after the request runs. You add it to debug a failing test and see what the endpoint actually returned.

open as a page

How do you run an MVC slice/integration test as an authenticated user without performing a real login? Explain @WithMockUser.

level: juniorimportance: must knowfreq 80%

basics

~20 s

Annotate the test method (or class) with @WithMockUser from spring-security-test. Before the test runs it seeds the SecurityContext with a fake authenticated user (default name 'user', role 'ROLE_USER'), so security checks pass without a real login.

open as a page

What is TestRestTemplate and when would you use it in a Spring Boot test?

level: juniorimportance: must knowfreq 70%

basics

~20 s

TestRestTemplate is a Spring Boot helper for calling your own running app over real HTTP in a test. You use it with @SpringBootTest(webEnvironment = RANDOM_PORT) to send actual requests to an embedded server and check the responses.

open as a page

What is WebTestClient and how do you use it to assert an HTTP endpoint's status and JSON body?

level: juniorimportance: must knowfreq 65%

basics

~10 s

WebTestClient is Spring's fluent HTTP test client. You call an endpoint, then chain assertions: get().uri(...).exchange().expectStatus().isOk().expectBody().jsonPath("$.name").isEqualTo("Ada").

open as a page

How do you assert on status, headers, and body with MockMvcResultMatchers, and how do content() and jsonPath() differ?

level: middleimportance: must knowfreq 70%

basics

~10 s

Chain andExpect with MockMvcResultMatchers: status().isOk() for the code, header().string("Location", "/x") for headers, and content().string(...)/content().json(...) or jsonPath("$.field").value(...) for the body.

open as a page

How do you document request and response fields with Spring REST Docs, and what happens if you leave a field undocumented?

level: middleimportance: must knowfreq 50%

basics

~10 s

Use PayloadDocumentation.responseFields(fieldWithPath("name").description("...")) inside document(). REST Docs is strict: if a field in the payload isn't documented (or a documented field is missing), the test fails, so docs stay complete.

open as a page

What are SecurityMockMvcRequestPostProcessors (user(), jwt(), csrf()) and how do they differ from @WithMockUser?

level: middleimportance: must knowfreq 70%

basics

~20 s

They are per-request modifiers you attach with MockMvc's .with(...). user(...) sets an authenticated principal on that request, jwt(...) sets a JWT-based authentication for resource-server tests, and csrf() adds a valid CSRF token. Unlike @WithMockUser they apply to a single request, imperatively.

open as a page

What are the differences between bindToServer, bindToController, and bindToApplicationContext when creating a WebTestClient?

level: middleimportance: must knowfreq 60%

basics

~20 s

bindToServer talks to a real running server over the network. bindToController and bindToApplicationContext use a mock server (no socket): the first wires up specific controllers, the second uses a whole Spring context including filters and config.

open as a page

What is the difference between MockMvcBuilders.standaloneSetup and webAppContextSetup, and when would you use each?

level: seniorimportance: must knowfreq 60%

basics

~20 s

standaloneSetup registers controllers manually with no Spring context — fast and focused but you wire everything yourself. webAppContextSetup builds MockMvc from a loaded WebApplicationContext, so real beans, filters, advice, and config apply — more realistic but heavier.

open as a page

What does `apply(springSecurity())` do when building a MockMvc, and why is it needed before using postprocessors like `user(...)` or `csrf()`?

level: seniorimportance: must knowfreq 55%

basics

~10 s

springSecurity() is a MockMvcConfigurer that wires Spring Security's filter chain into MockMvc. Without it, security filters don't run, so authentication/authorization and the csrf()/user() request postprocessors have no effect.

open as a page

TestRestTemplate is described as 'fault-tolerant.' What does that mean, and how does it differ from a plain RestTemplate on 4xx/5xx responses?

level: seniorimportance: must knowfreq 60%

basics

~20 s

Fault-tolerant means it does not throw exceptions on error responses. A plain RestTemplate throws HttpClientErrorException on 4xx and HttpServerErrorException on 5xx. TestRestTemplate installs a no-op error handler, so you just read response.getStatusCode() and assert on the error status.

open as a page

How do `content().string(...)` and the Hamcrest matcher overload of `jsonPath(...)` let you write richer assertions?

level: middleimportance: should knowfreq 45%

basics

~10 s

content().string(Matcher) runs a Hamcrest matcher against the raw body string (e.g. containsString("ok")). jsonPath("$.list").value(hasSize(3)) passes a Hamcrest matcher against a selected JSON value for flexible, non-equality checks.

open as a page

What is the difference between strict and lenient mode in `content().json(...)`, and when would you use each?

level: middleimportance: should knowfreq 60%

basics

~10 s

content().json(expected) compares the whole body as JSON. Lenient (default) allows extra fields and ignores array order; strict requires an exact match — same fields, no extras, and same array order.

open as a page

How do you test a file-upload (multipart) endpoint with MockMvc?

level: middleimportance: should knowfreq 45%

basics

~10 s

Use MockMvcRequestBuilders.multipart("/upload") and attach a MockMultipartFile with .file(...). The MockMultipartFile's first constructor arg (the name) must match the controller's @RequestParam / @RequestPart name.

open as a page

What are the ways to create a MockMvcTester, and how do create(), from(), and of() differ?

level: middleimportance: should knowfreq 45%

basics

~10 s

Three factories: MockMvcTester.create(mockMvc) wraps an existing MockMvc; MockMvcTester.from(webApplicationContext) builds one from the full context; MockMvcTester.of(controllers...) does a standalone setup with just the given controllers. Spring Boot 3.4+ also auto-configures an injectable bean.

open as a page

What is the difference between `MockMvcResultHandlers.print()` and `MockMvcResultHandlers.log()`?

level: middleimportance: should knowfreq 40%

basics

~10 s

Both dump the same request/response report. print() writes to System.out (always visible), while log() writes it through SLF4J/commons-logging at DEBUG level, so it only appears if that logger's DEBUG level is enabled.

open as a page

How do you test a secured endpoint with TestRestTemplate — for example sending HTTP Basic credentials?

level: middleimportance: should knowfreq 50%

basics

~20 s

Call rest.withBasicAuth("user", "password") — it returns a new TestRestTemplate that adds an HTTP Basic Authorization header to every request. Use the returned instance. Because it makes a real request, the whole Spring Security filter chain runs and you assert 200 vs 401/403.

open as a page

Explain RANDOM_PORT vs DEFINED_PORT with TestRestTemplate, and how you get the port if you need it.

level: middleimportance: should knowfreq 55%

basics

~20 s

RANDOM_PORT starts the embedded server on a free random port to avoid clashes; DEFINED_PORT uses the configured server.port (default 8080). The auto-configured TestRestTemplate handles the port for you via relative URLs, or you inject the actual port with @LocalServerPort.

open as a page

How does WebTestClient compare to MockMvc for testing Spring MVC endpoints, and how do you configure WebTestClient in a Spring Boot test?

level: middleimportance: should knowfreq 42%

basics

~10 s

Both 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.

open as a page

How do JSONPath assertions differ between MockMvc and WebTestClient?

level: seniorimportance: should knowfreq 40%

basics

~10 s

The JSONPath expression syntax is identical, but the assertion APIs differ. MockMvc uses jsonPath("$.x").value(...) (JsonPathResultMatchers) inside andExpect. WebTestClient uses .expectBody().jsonPath("$.x").isEqualTo(...) (JsonPathAssertions), a fluent chain with no static import.

open as a page

How do you assert on a JSON response body with MockMvcTester's bodyJson()?

level: seniorimportance: should knowfreq 50%

basics

~10 s

Call .bodyJson() after a request to get a JSON assert. Use .extractingPath("$.field") with JSONPath to check individual values, .convertTo(Type.class) to deserialize, or .isLenientlyEqualTo(...)/.isStrictlyEqualTo(...) to compare whole documents.

open as a page

How does MockMvcTester handle a controller exception that no @ExceptionHandler resolves, and how does that differ from classic MockMvc?

level: seniorimportance: should knowfreq 35%

basics

~20 s

MockMvcTester captures an unresolved handler exception in the result instead of throwing it out of the call. You assert on it with .hasFailed() and .failure(). Classic MockMvc rethrows the exception from perform(...), so you'd need assertThatThrownBy or expectedException.

open as a page

What are operation preprocessors in Spring REST Docs, and how do you use them to clean up captured snippets?

level: seniorimportance: should knowfreq 38%

basics

~10 s

Preprocessors transform the captured request/response before snippets are written — e.g. Preprocessors.prettyPrint() to format JSON, removeHeaders(...) to drop noise, maskLinks() to hide URIs. You attach them with document(id, preprocessRequest(...), preprocessResponse(...), snippets...).

open as a page

How does Spring REST Docs work with WebTestClient for a reactive/WebFlux application, and how does it differ from the MockMvc integration?

level: seniorimportance: should knowfreq 28%

basics

~10 s

Use the spring-restdocs-webtestclient module. Configure WebTestClient with WebTestClientRestDocumentation.documentationConfiguration, then call .consumeWith(WebTestClientRestDocumentation.document("id", ...)) on the response. Same snippets and descriptors as MockMvc, just a different entry-point class.

open as a page

How do `alwaysDo(...)` and `alwaysExpect(...)` on a MockMvc builder work, and when would you use them?

level: seniorimportance: should knowfreq 34%

basics

~10 s

They register a ResultHandler (alwaysDo) or ResultMatcher (alwaysExpect) once on the builder, and it runs automatically on every request performed by that MockMvc — so you don't repeat .andDo(...)/.andExpect(...) in each test.

open as a page

How do you authenticate a WebTestClient request in a reactive (WebFlux) test using spring-security-test?

level: seniorimportance: should knowfreq 45%

basics

~10 s

Use WebTestClient's mutateWith(...) with mutators from SecurityMockServerConfigurers, e.g. client.mutateWith(mockUser("alice").roles("ADMIN")). There are also mockJwt(), mockOpaqueToken(), and csrf() mutators. In WebFlux, authentication lives in the Reactor context, so these configure the exchange accordingly.

open as a page

showing 1–30 of 40