skip to content

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