JsonUnit

JsonUnit is a library that simplifies JSON comparison in tests.
APIs
There are several different APIs you can use. They all have more or less the same features, just the usage is
slightly different.
AssertJ integration
The recommended API is AssertJ integration which combines the power of JsonUnit and AssertJ.
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.json;
...
// compares two JSON documents (note lenient parsing of expected value)
assertThatJson("{\"a\":1, \"b\":2}").isEqualTo("{b:2, a:1}");
// objects are automatically serialized before comparison
assertThatJson(jsonObject).isEqualTo("{\n\"test\": 1\n}");
// AssertJ map assertions (numbers are converted to BigDecimals)
assertThatJson("{\"a\":1}").isObject().containsEntry("a", BigDecimal.valueOf(1));
// Type placeholders
assertThatJson("{\"a\":1, \"b\": {\"c\" :3}}")
.isObject().containsValue(json("{\"c\" :\"${json-unit.any-number}\"}"));
// AssertJ string assertion
assertThatJson("{\"a\": \"value\"")
.node("a").isString().isEqualTo("value");
// AssertJ array assertion
assertThatJson("{\"a\":[{\"b\": 1}, {\"c\": 1}, {\"d\": 1}]}")
.node("a").isArray().contains(json("{\"c\": 1}"));
// Can ignore array order
assertThatJson("{\"a\":[{\"b\": 1}, {\"c\": 1}, {\"d\": 1}]}")
.when(Option.IGNORING_ARRAY_ORDER).node("a").isArray()
.isEqualTo(json("[{\"c\": 1}, {\"b\": 1} ,{\"d\": 1}]"));
// custom matcher
assertThatJson("{\"test\":-1}")
.withConfiguration(c -> c.withMatcher("positive", greaterThan(valueOf(0))))
.isEqualTo("{\"test\": \"${json-unit.matches:positive}\"}");
// and
assertThatJson("{\"test\":{\"a\":1, \"b\":2, \"c\":3}}").and(
a -> a.node("test.a").isEqualTo(1),
a -> a.node("test.b").isEqualTo(2)
);
// JsonPath support
assertThatJson(json)
.inPath("$.store.book")
.isArray()
.contains(json(
" {\n" +
" \"category\": \"reference\",\n" +
" \"author\": \"Nigel Rees\",\n" +
" \"title\": \"Sayings of the Century\",\n" +
" \"price\": 8.96\n" +
" }"
));
JsonUnit tries to be clever when parsing the expected value. If the value can be parsed as valid JSON, it's
parsed so. If it can't be parsed, it's considered to be just a string to be compared. It usually works,
but it can lead to unexpected situations, usually with primitive values like numbers and booleans.
// This test does NOT pass. "1" is parsed as JSON containing number 1, the actual value is a string.
assertThatJson("{\"id\":\"1\", \"children\":[{\"parentId\":\"1\"}]}")
.inPath("children[*].parentId")
.isArray()
.containsOnly("1");
// You have to wrap the expected value by `JsonAssertions.value()`
// to prevent parsing
assertThatJson("{\"id\":\"1\", \"children\":[{\"parentId\":\"1\"}]}")
.inPath("children[*].parentId")
.isArray()
.containsOnly(value("1"));
// "true" is valid JSON so it gets parsed to primitive `true`
// Have to wrap it to JsonAssertions.value() in order to make sure it's not parsed
assertThatJson("{\"root\":[\"true\"]}").node("root").isArray().containsExactly(value("true"));
On the other hand, if you want to make sure that the expected value is parsed as JSON, use JsonAssertions.json().
Support for asInstanceOf
You can move between vanilla AssertJ and JsonUnit using asInstanceOf as in the following example:
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.JSON;
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
...
record DummyResponse(String trackingId, String json) {}
DummyResponse resp = new DummyResponse("abcd-0001", "{ \"foo\": \"bar\" }");
assertThat(resp)
.hasFieldOrPropertyWithValue("trackingId", "abcd-0001") // <- Assertj API
.extracting("json")
.asInstanceOf(JSON)
.isObject() // <- JsonUnit API
.containsEntry("foo", "bar");
Kotlin support
Following Kotlin API is supported (notice different import)
// Kotlin
import net.javacrumbs.jsonunit.assertj.assertThatJson
assertThatJson("""{"root":{"a":1, "b": 2}}""") {
isObject
node("root.a").isEqualTo(1)
node("root.b").isEqualTo(2)
}
To use AssertJ integration, import
<dependency>
<groupId>net.javacrumbs.json-unit</groupId>
<artifactId>json-unit-assertj</artifactId>
<version>6.0.1</version>
<scope>test</scope>
</dependency>
For more examples see the tests.
Hamcrests matchers
You use Hamcrest matchers in the following way
import static net.javacrumbs.jsonunit.JsonMatchers.*;
import static org.junit.Assert.*;
import static net.javacrumbs.jsonunit.core.util.ResourceUtils.resource;
...
assertThat("{\"test\":1}", jsonEquals("{\"test\": 1}"));
assertThat("{\"test\":1}", jsonPartEquals("test", 1));
assertThat("{\"test\":[1, 2, 3]}", jsonPartEquals("test[0]", 1));
assertThat("{\"test\":{\"a\":1, \"b\":2, \"c\":3}}",
jsonEquals("{\"test\":{\"b\":2}}").when(IGNORING_EXTRA_FIELDS));
// Can use other Hamcrest matchers too
assertThat("{\"test\":1}", jsonPartMatches("test", is(valueOf(1))))
assertThat("{\"test\":1}", jsonEquals(resource("test.json")));
To use import
<dependency>
<groupId>net.javacrumbs.json-unit</groupId>
<artifactId>json-unit</artifactId>
<version>6.0.1</version>
<scope>test</scope>
</dependency>
For more examples see the tests.
Spring MVC assertions
JsonUnit supports Spring MVC test assertions. For example
import static net.javacrumbs.jsonunit.spring.JsonUnitResultMatchers.json;
...
mockMvc.perform(get("/sample").andExpect(
json().isEqualTo("{\"result\":{\"string\":\"stringValue\", \"array\":[1, 2, 3],\"decimal\":1.00001}}")
);
mockMvc.perform(get("/sample").andExpect(
json().node("result.string2").isAbsent()
);
mockMvc.perform(get("/sample").andExpect(
json().inPath("$.result.array[1]").isEqualTo(2)
);
mockMvc.perform(get("/sample").andExpect(
json().node("result.array").when(Option.IGNORING_ARRAY_ORDER).isEqualTo(new int[]{3, 2, 1})
);
mockMvc.perform(get("/sample").andExpect(
json().node("result.array").matches(everyItem(lessThanOrEqualTo(valueOf(4))))
);
Following Kotlin DSL is supported:
mockMvc.get(path).andExpect {
jsonContent {
node("root").isEqualTo(CORRECT_JSON)
}
}
Inside jsonContent you have access to all AssertJ API capabilities as described here.
To use import
<dependency>
<groupId>net.javacrumbs.json-unit</groupId>
<artifactId>json-unit-spring</artifactId>
<version>6.0.1</version>
<scope>test</scope>
</dependency>
For more examples see the tests.
Spring WebTestClient
To integrate with Spring WebTest client do
import static net.javacrumbs.jsonunit.spring.WebTestClientJsonMatcher.json;
...
client.get().uri(path).exchange().expectBody().consumeWith(
json().isEqualTo("{\"result\":{\"string\":\"stringValue\", \"array\":[1, 2, 3],\"decimal\":1.00001}}")
);
client.get().uri(path).exchange().expectBody().consumeWith(
json().node("result.string2").isAbsent()
);
client.get().uri(path).exchange().expectBody().consumeWith(
json().inPath("$.result.array[1]").isEqualTo(2)
);
client.get().uri(path).exchange().expectBody().consumeWith(
json().node("result.array").when(Option.IGNORING_ARRAY_ORDER).isEqualTo(new int[]{3, 2, 1})
);
client.get().uri(path).exchange().expectBody().consumeWith(
json().node("result.array").matches(everyItem(lessThanOrEqualTo(valueOf(4))))
);
For Kotlin, you can use our bespoke DSL
import net.javacrumbs.jsonunit.spring.jsonContent
...
client.get().uri(path).exchange().expectBody()
.jsonContent {
isEqualTo(CORRECT_JSON)
}
Import
<dependency>
<groupId>net.javacrumbs.json-unit</groupId>
<artifactId>json-unit-spring</artifactId>
<version>6.0.1</version>
<scope>test</scope>
</dependency>
For more examples see the tests.
Spring RestTestClient
Spring RestTestClient is a new testing utility introduced in Spring Framework that combines features of MockMvc and WebTestClient. JsonUnit provides seamless integration with it.
import static net.javacrumbs.jsonunit.spring.RestTestClientJsonMatcher.json;
...
client.get().uri(path).accept(MediaType.APPLICATION_JSON)
.exchange()
.expectBody()
.consumeWith(json().isEqualTo(CORRECT_JSON));
client.get().uri(path).exchange().expectBody()
.consumeWith(json().node("result.string").isEqualTo("stringValue"));
client.get().uri(path).exchange().expectBody()
.consumeWith(json().inPath("$.result.array[1]").isEqualTo(2));
client.get().uri(path).exchange().expectBody()
.consumeWith(json().node("result.array")
.when(Option.IGNORING_ARRAY_ORDER)
.isEqualTo(new int[]{3, 2, 1}));
For Kotlin, you can use the DSL:
import net.javacrumbs.jsonunit.spring.jsonContent
...
client.get().uri(path).accept(APPLICATION_JSON)
.exchange()
.expectBody()
.jsonContent { isEqualTo(CORRECT_JSON) }
client.get().uri(path).exchange()
.expectBody()
.jsonContent {
node("result.string").isString().isEqualTo("stringValue")
}
To use import
<dependency>
<groupId>net.javacrumbs.json-unit</groupId>
<artifactId>json-unit-spring</artifactId>
<version>6.0.1</version>
<scope>test</scope>
</dependency>
For more examples see the tests.
Spring AssertJ for MockMvc
Since version 4