What is @JsonTest and what does JacksonTester give you?
answer
- Slice = JSON layer only
- Uses app's real ObjectMapper + @JsonComponent
- JacksonTester.write -> JsonContent
- parseObject -> back to object
- extractingJsonPath... / isEqualToJson(file)
basics
~20 s@JsonTest is a Spring Boot slice for testing JSON serialization. It configures your app's Jackson (or Gson) setup and gives you a JacksonTester helper to serialize/deserialize objects and assert the resulting JSON, without starting the whole app.
solid answer
~30 s@JsonTest is a narrow Spring Boot test slice that loads only the JSON infrastructure — your application's configured Jackson `ObjectMapper` (plus Gson/JSON-B if present), including any custom modules and `@JsonComponent` beans. It then provides tester helpers you `@Autowired`: `JacksonTester<T>` (and `GsonTester`, `JsonbTester`, `BasicJsonTester`). `JacksonTester.write(obj)` serializes an object to a `JsonContent`, on which you run AssertJ-style assertions like `extractingJsonPathStringValue("$.name")` or `isEqualToJson("expected.json")` to compare against a classpath file. `parse`/`parseObject` deserialize JSON back into objects. It is faster and more focused than @SpringBootTest and lets you pin the exact wire format of your DTOs — field names, formatting, null handling — in isolation.
code
java · 21 lines@JsonTest
class EmployeeJsonTest {
@Autowired
private JacksonTester<Employee> json; // auto-initialized by the slice
@Test
void serializesToExpectedShape() throws Exception {
JsonContent<Employee> result = json.write(new Employee("Ada", 42));
assertThat(result).extractingJsonPathStringValue("$.name").isEqualTo("Ada");
assertThat(result).extractingJsonPathNumberValue("$.age").isEqualTo(42);
assertThat(result).isEqualToJson("employee.json"); // classpath file
}
@Test
void deserializesFromJson() throws Exception {
Employee e = json.parseObject("{\"name\":\"Ada\",\"age\":42}");
assertThat(e.getName()).isEqualTo("Ada");
}
}go deeper
Know it tests JSON serialization with JacksonTester and assertions like isEqualToJson.
Explain that it loads the app's real Jackson config (modules, @JsonComponent) and how to serialize vs deserialize and assert JSON paths.
Discuss pinning wire contracts, lenient vs strict compare, JsonContent path assertions, and when to prefer @JsonTest over @WebMvcTest.
Frame @JsonTest as contract-testing for DTOs, note coupling to global Jackson config, and set team conventions for expected-JSON fixtures and enum/date representations.
## What it is `@JsonTest` (`org.springframework.boot.test.autoconfigure.json.JsonTest`) is a Spring Boot **test slice** that stands up only the **JSON marshalling layer** of your app — not controllers, not the DB, not services. ## What it auto-configures It applies your application's JSON configuration so the test uses the *same* serialization rules as production: - the auto-configured **Jackson `ObjectMapper`** with all registered Jackson **modules** (e.g. JavaTime for `java.time`) and any **`@JsonComponent`** custom serializers/deserializers you defined, - **Gson** and **JSON-B** equivalents if those libraries are on the classpath, - and the **tester** helper beans. ## The testers You inject a typed tester as a field: - **`JacksonTester<T>`** — Jackson-backed; the most common. - **`GsonTester<T>`**, **`JsonbTester<T>`** — same idea for Gson / JSON-B. - **`BasicJsonTester`** — not typed; works on raw JSON strings for path assertions only (no object binding). Key methods on `JacksonTester<T>`: - **`write(T object)`** → returns a **`JsonContent<T>`** (serialization / 'object → JSON'). - **`parse(String json)`** → `ObjectContent<T>`; **`parseObject(String json)`** → the `T` instance directly (deserialization / 'JSON → object'). - `read(...)` overloads read JSON from classpath resources. ## Assertions `JsonContent` integrates with AssertJ via `assertThat(...)`: - **JSON-path value checks**: `extractingJsonPathStringValue("$.name").isEqualTo("Ada")`, `...NumberValue`, `...BooleanValue`, `...ArrayValue`, plus `hasJsonPathValue`/`doesNotHaveJsonPath`. - **Whole-document compare**: `isEqualToJson("employee.json")` compares (order-insensitively) against a JSON file on the classpath, or `isStrictlyEqualToJson(...)`. This uses the underlying JSONAssert/JsonPath support. ## How the tester gets initialized Because `JacksonTester<T>` is generic, it needs the field's type info. Under `@JsonTest`, Spring Boot **initializes any tester fields automatically** (it calls `JacksonTester.initFields(...)` for you). If you construct the test object yourself outside the slice, you must call `JacksonTester.initFields(this, objectMapper)` manually — otherwise the tester is null. ## When to use it Use `@JsonTest` to lock down the **exact wire contract** of your DTOs: property names, date/number formatting, enum representation, `@JsonIgnore`/`@JsonProperty` behavior, and round-trip fidelity — cheaply and in isolation, independent of any controller. For a full controller-plus-JSON test you'd use `@WebMvcTest`, but that is heavier and mixes concerns. ## Gotchas - A `NullPointerException` on the tester usually means it was not initialized (test not run under the slice, or `initFields` missing). - `isEqualToJson("file.json")` resolves the file **relative to the test class package** on the classpath by default. - The slice honors your real Jackson config, so a global setting (e.g. `WRITE_DATES_AS_TIMESTAMPS=false`) affects the output — that is the point, but it can surprise you.
- Your JacksonTester field is null at runtime — what went wrong?The tester was not initialized. Under @JsonTest Spring auto-calls JacksonTester.initFields; if you instantiate the test outside the slice you must call JacksonTester.initFields(this, objectMapper) yourself, or the generic tester stays uninitialized/null.
- Difference between isEqualToJson and extractingJsonPathStringValue?isEqualToJson compares the whole document against an expected JSON (file or string), order-insensitively by default. extractingJsonPathStringValue asserts a single value at a JSON path, useful when you only care about specific fields.
saying these in an interview costs you the question
- Thinking @JsonTest starts controllers or the web layer (that is @WebMvcTest).
- Believing it uses a fresh default ObjectMapper rather than the app's configured one.
- Confusing write() (serialize) with parse()/parseObject() (deserialize).
- Assuming isEqualToJson does a strict, order-sensitive compare by default (it is lenient; use isStrictlyEqualToJson for strict).