JSON is a popular data format that is widely used in the communication between systems.
Most of the time, I see it being sent with an HTTP request or as the content of a message in a message bus.
To ensure the stability of the communication between such systems, it is important that the structure of the JSON does not change without the agreement of both participants.
With @JsonTest
, Spring Boot contains a handy tool to test the serialization of Java objects into JSON and vice versa.
What exactly is a @JsonTest?
@JsonTest
is one of Spring Boot’s test slices. This means it will start an ApplicationContext
where everything related to the JSON mapping – and nothing else – is configured exactly according to your application’s runtime.
Currently, it supports Jackson, Gson and Jsonb.
If you are using Jackson, the ObjectMapper
, all Jackson modules and all components annotated with @JsonComponent
will be loaded, as well.
To use @JsonTest
, you need to include the dependency org.springframework.boot:spring-boot-starter-test in your project.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
Testing the JSON serialization
To give an example, we want to test the correct serialization of the given class Book
.
public class Book {
private String title;
private String author;
private String isbn;
//... constructor, getters and setters
}
@JsonTest
, we can make sure that the schema of the serialized object won’t be changed by accident and stays as shown here:
{"title":"...", "author":"...", "isbn":"..."}
The code of our serialization test could look something like this:
@JsonTest
public class BookJsonTest {
@Autowired
private JacksonTester<Book> json;
@Test
public void testSerialization() throws Exception {
var book = new Book("Spring Boot 2", "Michael Simons", "978-3-86490-525-4");
var expectedJson = "{\"title\":\"Spring Boot 2\",\"author\":\"Michael Simons\",\"isbn\":\"978-3-86490-525-4\"}";
assertThat(json.write(book)).isEqualToJson(expectedJson);
}
// ... test for deserialization
}
The injected JacksonTester
is used to expose Assert
s which are used in combination with AssertJ to test the JSON content.
If you are using Gson or Jsonb, you have to use its sibling GsonTester
or JsonbTester
.
The Assert
returned by isEqualToJson()
is used to compare the serialized book
with a complete JSON string – in this case, expectedJson
.
For more granular testing of single fields, we could also use the hasJsonPathValue()
method.
//...
assertThat(json.write(book)).hasJsonPathValue("$.title", "Spring Boot 2");
//...
Testing the JSON deserialization
If our system receives JSON formatted information, we should make sure that we don’t accidentally break the deserialization of a JSON string into an object. This test can also be automated with the help of @JsonTest
.
@JsonTest
public class BookJsonTest {
@Autowired
private JacksonTester<Book> json;
// ... test for serialization
@Test
public void testDeserialization() throws Exception {
var jsonValue = "{\"title\":\"Spring Boot 2\",\"author\":\"Michael Simons\",\"isbn\":\"978-3-86490-525-4\"}";
var expectedBook = new Book("Spring Boot 2", "Michael Simons", "978-3-86490-525-4");
assertThat(json.parse(jsonValue)).usingRecursiveComparison.isEqualTo(expectedBook);
}
}
JacksonTester
exposes Assert
s to test your JSON content.
The Assert
returned by usingRecursiveComparison()
is used for a recursive field by field comparison of the parsed jsonValue
with the expectedBook
.
Conclusion
The JacksonTester
and its siblings provide a great set of Assert
s.
Use them to make sure that the schemas of the messages that you send to other systems are not altered by accident. If you are receiving messages from other systems, you can use them to ensure that you can always parse these messages.
Thanks to the @JsonTest
annotation, the ApplicationContext that is loaded for your integration tests contains only the classes that are needed for the JSON mapping. This can significantly reduce the execution time of your tests.
When not to use it?
If you want to test the JSON response of your @RestController
, I would recommend using the @WebMvcTest
test slice.
Resources
- you can find the code of this Blog Post in this GitHub repository.
- have a look at Spring Boot’s documentation for more official information about
@JsonTest