Spring Boot - Testing JSON Serialization and Deserialization With @JsonTest - Example

In this section, we will learn how to test JSON Serialization and Deserialization With @JsonTest in Spring Boot application.

1. @JsonTest

Instead of bootstrapping the entire application context for every test, @JsonTest initializes the Spring application context with only those beans needed to test JSON serialization and deserialization.
@JsonTest annotation can be used to test slices of our application and the auto-configuration that it import by default are listed below:
  • org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration
  • org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration
  • org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
  • org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration
  • org.springframework.boot.test.autoconfigure.json.JsonTestersAutoConfiguration

Testing JSON Serialization and Deserialization Example

2. Creating a spring boot application

First, open the Spring initializr https://start.spring.io

Then, Provide the Group and Artifact name. We have provided Group name com.knf.dev.demo and Artifact json-example. Here I selected the Maven project - language Java 17 - Spring Boot 3.1.5, and Spring Web.


Then, click on the Generate button. When we click on the Generate button, it starts packing the project in a .zip(jsontest-example) file and downloads the project. Then, Extract the Zip file. 

Then, import the project on your favourite IDE.

Final Project Directory:


Complete pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<
modelVersion>4.0.0</modelVersion>
<
parent>
<
groupId>org.springframework.boot</groupId>
<
artifactId>spring-boot-starter-parent</artifactId>
<
version>3.1.5</version>
<
relativePath/> <!-- lookup parent from repository -->
</parent>
<
groupId>com.knf.dev.demo</groupId>
<
artifactId>jsontest-example</artifactId>
<
version>0.0.1-SNAPSHOT</version>
<
name>jsontest-example</name>
<
description>Demo project for Spring Boot</description>
<
properties>
<
java.version>17</java.version>
</
properties>
<
dependencies>
<
dependency>
<
groupId>org.springframework.boot</groupId>
<
artifactId>spring-boot-starter-web</artifactId>
</
dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

</
dependencies>

<
build>
<
plugins>
<
plugin>
<
groupId>org.springframework.boot</groupId>
<
artifactId>spring-boot-maven-plugin</artifactId>
<
configuration>
<
image>
<
builder>paketobuildpacks/builder-jammy-base:latest</builder>
</
image>
</
configuration>
</
plugin>
</
plugins>
</
build>

</
project>

spring-boot-starter-test starter will provide following libraries:

  • JUnit 
  • Spring Test & Spring Boot Test 
  • AssertJ
  • Hamcrest 
  • Mockito 
  • JSONassert 
  • JsonPath 


Create UserDTO

package com.knf.dev.demo.dto;

import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDate;
import java.util.Map;

public class UserDTO {

private String name;
private String email;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private LocalDate dob;
private Map<String, String> roles;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public LocalDate getDob() {
return dob;
}

public void setDob(LocalDate dob) {
this.dob = dob;
}

public Map<String, String> getRoles() {
return roles;
}

public void setRoles(Map<String, String> roles) {
this.roles = roles;
}
}

Create user.json inside resource directory

{
"name":"Sibin",
"email":"sibin@gmail.com",
"dob":"1970-01-09",
"roles":{
"role1":"Admin",
"role2":"Editor"
}
}
We are using this JSON data for our testing purposes later.

JsontestExampleApplication.java

package com.knf.dev.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class JsontestExampleApplication {

public static void main(String[] args) {
SpringApplication.run(JsontestExampleApplication.class, args);
}

}

Write Unit test for JSON Serialization and Deserialization

Let’s write our test cases by creating UserDTOTests class

Create UserDTOTests

When using JUnit 4, this annotation should be used in combination with @RunWith(SpringRunner.class). But for this example  we are using JUnit 5, there’s no need to add the equivalent @ExtendWith(SpringExtension.class).
package com.knf.dev.demo;

import com.knf.dev.demo.dto.UserDTO;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.json.JsonTest;
import org.springframework.boot.test.json.JacksonTester;
import org.springframework.boot.test.json.JsonContent;
import org.springframework.boot.test.json.ObjectContent;
import org.springframework.core.io.Resource;
import org.springframework.util.StreamUtils;

import java.nio.charset.Charset;
import java.time.LocalDate;
import java.time.Month;
import java.util.HashMap;
import java.util.Map;

import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;

@JsonTest
public class UserDTOTests {


@Autowired
private JacksonTester<UserDTO> jacksonTester;

@Value("classpath:user.json")
Resource userResource;

@Test
void serializeInCorrectFormat() throws Exception {

UserDTO userDTO = new UserDTO();
userDTO.setEmail("sibin@gmail.com");
userDTO.setName("Sibin");

LocalDate dob = LocalDate.of(1970, Month.JANUARY, 9);
userDTO.setDob(dob);

Map<String,String> roles= new HashMap<>();
roles.put("role1","Admin");
roles.put("role2","Editor");
userDTO.setRoles(roles);

JsonContent<UserDTO> json = jacksonTester.write(userDTO);

// Assert against a `user.json` file
assertThat(json).isEqualToJson(userResource);

// JSON path based assertions
assertThat(json).hasJsonPathStringValue("@.email");
assertThat(json).extractingJsonPathStringValue("@.dob")
.isEqualTo("1970-01-09");
assertThat(json).extractingJsonPathStringValue("@.name")
.isEqualTo("Sibin");
assertThat(json).extractingJsonPathMapValue("@.roles").
hasFieldOrProperty("role1");
assertThat(json).extractingJsonPathMapValue("@.roles").
extractingByKey("role1").isEqualTo("Admin");
}

@Test
void deserializeFromCorrectFormat() throws Exception {

//Convert Resource to String
String json = StreamUtils.copyToString(userResource.getInputStream(),
Charset.defaultCharset());

UserDTO userDTO = jacksonTester.parseObject(json);

assertThat(userDTO.getEmail()).isEqualTo("sibin@gmail.com");
assertThat(userDTO.getName()).isEqualTo("Sibin");
assertThat(userDTO.getDob()).isEqualTo("1970-01-09");
assertThat(userDTO.getRoles().size()).isEqualTo(2);
}
}
  • JacksonTester is a AssertJ based JSON tester backed by Jackson. If you are using Gson or Jsonb, you have to use its sibling GsonTester or JsonbTester.
  • Here JsonContent is created from a JSON tester. jacksonTester.write(userDTO) returns JsonContent.
  • assertThat is used to check the specified value matches the expected value. It will accept the two parameters, the first contains the actual value, and the second will have the object matching the condition.
  • hasJsonPathStringValue() method is used to check that the actual value at the given JSON path produces a non-null string result.
  • extractingJsonPathStringValue() is used to extract the string value at the given JSON path.
  • extractingJsonPathMapValue() method is used extract the map value at the given JSON path.
  • extractingByKey() method is used to extract the value of given key from the map under test.
  • parseObject() is used to return the object created from parsing the specific JSON String.

3. Run the test


Or you can run the test using following command:

mvn  test -Dtest=UserDTOTests

Comments

Popular posts from this blog

Spring Boot OpenAI Integration: Step-by-Step Guide

Orchestration-Based Saga Architecture and Spring Boot Microservices Implementation Guide

Spring Boot 3 + Angular 15 + Material - Full Stack CRUD Application Example