GithubHelp home page GithubHelp logo

jsonunit's Introduction

JsonUnit Apache License 2 Build Status Maven Central

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().

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>3.2.7</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>3.2.7</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().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>3.2.7</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().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>3.2.7</version>
    <scope>test</scope>
</dependency>

For more examples see the tests.

Spring REST client assertions

import static net.javacrumbs.jsonunit.spring.JsonUnitRequestMatchers.json;
...
mockServer.expect(requestTo(URI))
      .andExpect(json().isEqualTo(json))
      .andRespond(withSuccess(jsonResponse, MediaType.APPLICATION_JSON_UTF8));

To use import

<dependency>
    <groupId>net.javacrumbs.json-unit</groupId>
    <artifactId>json-unit-spring</artifactId>
    <version>3.2.7</version>
    <scope>test</scope>
</dependency>

For more examples see the tests.

Kotest assertions

JsonUnit supports Kotest assertions.

Import:

<dependency>
    <groupId>net.javacrumbs.json-unit</groupId>
    <artifactId>json-unit-kotest</artifactId>
    <version>3.2.7</version>
    <scope>test</scope>
</dependency>

And enjoy:

"""{"test":1}""" should equalJson("""{"test": 1}""")

// Provide configuration
"""{"test":1.01}""" should equalJson("""{"test":1}""", configuration { withTolerance(0.1) })

// Use inPath
"""{"test":1}""" inPath "test" should equalJson("1")

// Clues with nesting
"""{"test": {"nested": 1}}""".inPath("test").asClue {
    it inPath "nested" should equalJson("2")
}

"""{"test":1}""".inPath("test").shouldBeJsonNumber()
    // shouldBeJsonNumber returns BigDecimal, so we can use standard kotest assertions
    // PLease note that numbers are converted to BigDecimals
    .shouldBeEqualComparingTo(valueOf(1))

// The same for arrays generated by JsonPath
"""{"test": [{"a": "a"}, {"a": true}, {"a": null}, {"a": 4}]}""".inPath("$.test[*].a")
    .shouldBeJsonArray()
    .shouldContainExactly("a", true, null, valueOf(4))

// ... and objects
"""{"a":1, "b": true}""".shouldBeJsonObject().shouldMatchAll(
    "a" to { it should beJsonNumber() },
    "b" to { it should beJsonBoolean() }
)

See the tests for more examples.

Features

JsonUnit support all this features regardless of API you use.

JsonPath support

You can use JsonPath navigation together with JsonUnit. It has native support in AssertJ integration so you can do something like this:

// AssertJ style
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" +
            "            }"
    ));

For the other API styles you have to first import JsonPath support module

<dependency>
    <groupId>net.javacrumbs.json-unit</groupId>
    <artifactId>json-unit-json-path</artifactId>
    <version>3.2.7</version>
    <scope>test</scope>
</dependency>

and then use instead of actual value

import static net.javacrumbs.jsonunit.jsonpath.JsonPathAdapter.inPath;

...
// Fluent assertions
assertThatJson(inPath(json, "$.store.book[*].author"))
    .when(Option.IGNORING_ARRAY_ORDER)
    .isEqualTo("['J. R. R. Tolkien', 'Nigel Rees', 'Evelyn Waugh', 'Herman Melville']");

Ignoring values

Sometimes you need to ignore certain values when comparing. It is possible to use ${json-unit.ignore} or #{json-unit.ignore} placeholder like this

// AssertJ API
assertThatJson("{\"a\":1}")
    .isEqualTo(json("{\"a\":\"${json-unit.ignore}\"}"));

Please note that the assertion will fail if the test element is missing in the actual value.

Ignoring elements

If the element needs to be ignored completely you can use ${json-unit.ignore-element} placeholder.

// AssertJ API
assertThatJson("{\"root\":{\"test\":1, \"ignored\": null}}")
      .isEqualTo("{\"root\":{\"test\":1, \"ignored\": \"${json-unit.ignore-element}\"}}");

The assertion will not fail if the element is missing in the actual value.

Ignoring paths

whenIgnoringPaths configuration option makes JsonUnit ignore the specified paths in the actual value. If the path matches, it's completely ignored. It may be missing, null or have any value. Also when(paths(...), thenIgnore() can be used.

// AssertJ style
assertThatJson("{\"root\":{\"test\":1, \"ignored\": 1}}")
    .whenIgnoringPaths("root.ignored"))
    .isEqualTo("{\"root\":{\"test\":1}}");

// Hamcrest matcher
assertThat(
  "{\"root\":{\"test\":1, \"ignored\": 2}}",
  jsonEquals("{\"root\":{\"test\":1, \"ignored\": 1}}").whenIgnoringPaths("root.ignored")
);

Array index placeholder

assertThatJson("[{\"a\":1, \"b\":2},{\"a\":1, \"b\":3}]")
    .whenIgnoringPaths("[*].b")
    .isEqualTo("[{\"a\":1, \"b\":0},{\"a\":1, \"b\":0}]");

Please note that if you use JsonPath, you should start the path to be ignored by $ Also note that whenIgnoringPaths method supports full JsonPath syntax only in AssertJ API, all the other flavors support only exact path or array index placeholder as described above.

JsonPath with whenIgnoringPaths example:

// AssertJ API
assertThatJson("{\"fields\":[" +
        "{\"key\":1, \"name\":\"AA\"}," +
        "{\"key\":2, \"name\":\"AB\"}," +
        "{\"key\":3, \"name\":\"AC\"}" +
    "]}")
    .whenIgnoringPaths("$.fields[?(@.name=='AA')].key")
    .isEqualTo("{\"fields\":[" +
        "{\"key\":2, \"name\":\"AA\"}," +
        "{\"key\":2, \"name\":\"AB\"}," +
        "{\"key\":3, \"name\":\"AC\"}" +
    "]}");

Regular expressions

It is also possible to use regular expressions to compare string values

assertThatJson("{\"test\": \"ABCD\"}")
    .isEqualTo("{\"test\": \"${json-unit.regex}[A-Z]+\"}");

For matching just part of the string, you can use this (we have to escape twice, once for Java, once for JSON)

assertThatJson("{\"test\": \"This is some text followed by: ABCD, followed by this\"}")
            .isEqualTo("{\"test\": \"${json-unit.regex}^\\\\QThis is some text followed by: \\\\E[A-Z]+\\\\Q, followed by this\\\\E$\"}");

Since this is quite hard to write, you can implement an expression builder like this.

Type placeholders

If you want to assert just a type, but you do not care about the exact value, you can use any-* placeholder like this

assertThatJson("{\"test\":\"value\"}")
    .isEqualTo("{test:'${json-unit.any-string}'}");

assertThatJson("{\"test\":true}")
    .isEqualTo("{\"test\":\"${json-unit.any-boolean}\"}");

assertThatJson("{\"test\":1.1}")
    .isEqualTo("{\"test\":\"${json-unit.any-number}\"}");

You can also use hash instead of string #{json-unit.any-string} for example if you are using language with string interpolation like Kotlin.

Custom matchers

In some special cases you might want to use your own matcher in the expected document.

 assertThatJson("{\"test\":-1}")
             .withMatcher("positive", greaterThan(valueOf(0)))
             .isEqualTo("{\"test\": \"${json-unit.matches:positive}\"}");

In even more special cases, you might want to parametrize your matcher.

 Matcher<?> divisionMatcher = new DivisionMatcher();
 assertThatJson("{\"test\":5}")
    .withMatcher("isDivisibleBy", divisionMatcher)
    .isEqualTo("{\"test\": \"${json-unit.matches:isDivisibleBy}3\"}");

 private static class DivisionMatcher extends BaseMatcher<Object> implements ParametrizedMatcher {
     private BigDecimal param;

     public boolean matches(Object item) {
         return ((BigDecimal)item).remainder(param).compareTo(ZERO) == 0;
     }

     public void describeTo(Description description) {
         description.appendValue(param);
     }

     @Override
     public void describeMismatch(Object item, Description description) {
         description.appendText("It is not divisible by ").appendValue(param);
     }

     public void setParameter(String parameter) {
         this.param = new BigDecimal(parameter);
     }
 }

If you need a matcher with more than one parameter, you can implement it like this.

Options

There are multiple options how you can configure the comparison

TREATING_NULL_AS_ABSENT - fields with null values are equivalent to absent fields. For example, this test passes

assertThatJson("{\"test\":{\"a\":1, \"b\": null}}")
    .when(TREATING_NULL_AS_ABSENT)
    .isEqualTo("{\"test\":{\"a\":1}}");

IGNORING_ARRAY_ORDER - ignores order in arrays

assertThatJson("{\"test\":[1,2,3]}")
    .when(IGNORING_ARRAY_ORDER)
    .isEqualTo("{\"test\":[3,2,1]}");

IGNORING_EXTRA_ARRAY_ITEMS - ignores unexpected array items

assertThatJson("{\"test\":[1,2,3,4]}")
    .when(IGNORING_EXTRA_ARRAY_ITEMS)
    .isEqualTo("{\"test\":[1,2,3]}");


assertThatJson("{\"test\":[5,5,4,4,3,3,2,2,1,1]}")
    .when(IGNORING_EXTRA_ARRAY_ITEMS, IGNORING_ARRAY_ORDER)
    .isEqualTo("{\"test\":[1,2,3]}");

IGNORING_EXTRA_FIELDS - ignores extra fields in the compared value

assertThatJson("{\"test\":{\"a\":1, \"b\":2, \"c\":3}}")
    .when(IGNORING_EXTRA_FIELDS)
    .isEqualTo("{\"test\":{\"b\":2}}");

IGNORE_VALUES - ignores values and compares only types

assertThatJson("{\"a\":2,\"b\":\"string2\"}")
    .when(paths("a", "b"), then(IGNORING_VALUES))
    .isEqualTo("{\"a\":1,\"b\":\"string\"}");

It is possible to combine options.

assertThatJson("{\"test\":[{\"key\":3},{\"key\":2, \"extraField\":2},{\"key\":1}]}")
    .when(IGNORING_EXTRA_FIELDS, IGNORING_ARRAY_ORDER)
    .isEqualTo("{\"test\":[{\"key\":1},{\"key\":2},{\"key\":3}]}");

In Hamcrest assertion you can set the option like this

assertThat("{\"test\":{\"a\":1, \"b\":2, \"c\":3}}",
    jsonEquals("{\"test\":{\"b\":2}}").when(IGNORING_EXTRA_FIELDS));

You can define options locally (for specific paths) by using when(path(...), then(...)):

// ignore array order for [*].a
// AssertJ
assertThatJson("{\"test\":{\"a\":1,\"b\":2,\"c\":3}}").when(paths("test.c"), then(IGNORING_VALUES))
    .isEqualTo("{\"test\":{\"a\":1,\"b\":2,\"c\":4}}");
// ignore array order everywhere but [*].b
assertThatJson("[{\"b\":[4,5,6]},{\"b\":[1,2,3]}]")
    .when(IGNORING_ARRAY_ORDER)
    .when(path("[*].b"), thenNot(IGNORING_ARRAY_ORDER))
    .isEqualTo("[{\"b\":[1,2,3]},{\"b\":[4,5,6]}]");
// ignore extra fields in the object "a"
assertThatJson("{\"a\":{\"a1\":1,\"a2\":2},\"b\":{\"b1\":1,\"b2\":2}}")
    .when(path("a"), then(IGNORING_EXTRA_FIELDS))
    .isEqualTo("{\"a\":{\"a1\":1},\"b\":{\"b1\":1}}"))
// ignore extra array items in the array
assertThatJson("{\"a\":[1,2,3]}")
    .when(path("a"), then(IGNORING_EXTRA_ARRAY_ITEMS))
    .isEqualTo("{\"a\":[1,2]}");
// Hamcrest
assertThat("{\"test\":{\"a\":1,\"b\":2,\"c\":3}}",
    jsonEquals("{\"test\":{\"a\":1,\"b\":2,\"c\":4}}").when(path("test.c"), then(IGNORING_VALUES)));

Note that TREATING_NULL_AS_ABSENT and IGNORING_VALUES require exact paths to ignored fields:

// ignoring number and str
assertThatJson("{\"a\":2,\"b\":\"string2\"}")
    .when(paths("a", "b"), then(IGNORING_VALUES))
    .isEqualTo("{\"a\":1,\"b\":\"string\"}");
// treat null B as absent B
assertThatJson("{\"A\":1,\"B\":null}")
    .when(path("B"), then(TREATING_NULL_AS_ABSENT))
    .isEqualTo("{\"A\":1}");

All other options require paths to objects or arrays where values or order should be ignored.

Array indexing

You can use negative numbers to index arrays form the end

assertThatJson("{\"root\":{\"test\":[1,2,3]}}")
    .node("root.test[-1]").isEqualTo(3);

Numerical comparison

Numbers are by default compared in the following way:

  • If the type differs, the number is different. So 1 and 1.0 are different (int vs. float). This does not apply when Moshi is used since it parses all numbers as Doubles.
  • Floating number comparison is exact, down to the scale - 1.0 and 1.00 are considered to be different.

You can change this behavior by setting tolerance. If you set tolerance to 0 two numbers are considered equal if they are equal mathematically even though they have different type or precision (a.compareTo(b) == 0)).

assertThatJson("{\"test\":1.00}").node("test").withTolerance(0).isEqualTo(1);

If you set tolerance to non-zero value, the values are considered equal if abs(a-b) <= tolerance.

assertThatJson("{\"test\":1.00001}").node("test").withTolerance(0.001).isEqualTo(1);

Or you can use Hamcrest matcher

import static java.math.BigDecimal.valueOf;
...
assertThatJson("{\"test\":1.10001}").node("test")
    .matches(closeTo(valueOf(1.1), valueOf(0.001)));

If you are interested why 1 and 1.0 are treated as different numbers please read this comment.

If you want to have special handling of numerical values, you can inject your own number comparator.

assertThatJson("{\"a\":1.0}")
    .withConfiguration(c -> c.withNumberComparator(numberComparator))
    .isEqualTo("{\"a\":1.00}");

Escaping dots

Sometimes you have dots in JSON element names, and you need to address those elements. It is possible to escape dots like this

assertThatJson("{\"name.with.dot\": \"value\"}").node("name\\.with\\.dot").isStringEqualTo("value");

Lenient parsing of expected value

Writing JSON string in Java is huge pain. JsonUnit parses expected values leniently, so you do not have to quote keys, and you can use single quotes instead of double quotes. Please note that the actual value being compared is parsed in strict mode.

assertThatJson("{\"a\":\"1\", \"b\":2}").isEqualTo("{b:2, a:'1'}");

Jackson Object Mapper customization

If you need to customize Jackson 2 Object Mapper, you can do using SPI. Implement net.javacrumbs.jsonunit.providers.Jackson2ObjectMapperProvider.

public class Java8ObjectMapperProvider implements Jackson2ObjectMapperProvider {
    private final ObjectMapper mapper;

    private final ObjectMapper lenientMapper;


    public Java8ObjectMapperProvider() {
        mapper = new ObjectMapper().registerModule(new JavaTimeModule());
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

        lenientMapper = new ObjectMapper().registerModule(new JavaTimeModule());
        lenientMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        lenientMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
        lenientMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
    }

    @Override
    public ObjectMapper getObjectMapper(boolean lenient) {
        return lenient ? lenientMapper : mapper;
    }
}

and register it in META-INF/services/net.javacrumbs.jsonunit.providers.Jackson2ObjectMapperProvider. See this example.

Logging

Although the differences are printed out by the assert statement, sometimes you use JsonUnit with other libraries like Jadler that do not print the differences between documents. In such case, you can switch on the logging. JsonUnit uses SLF4J. The only thing you need to do is to configure your logging framework to log net.javacrumbs.jsonunit.difference on DEBUG level.

DifferenceListener

If you need better difference reporting, you can implement DifferenceListener and use it this way

assertThatJson("{\"test\":-1}")
    .withDifferenceListener(listener)
    .isEqualTo(json);

Selecting underlying library

JsonUnit is trying to cleverly match which JSON library to use. In case you need to change the default behavior, you can use json-unit.libraries system property. For example -Djson-unit.libraries=jackson2,gson or System.setProperty("json-unit.libraries", "jackson2");. Supported values are gson, json.org, moshi, jackson2

Licence

JsonUnit is licensed under Apache 2.0 licence.

Release notes

3.2.7 (2024-02-21)

  • #483 More optimal fix for JsonPath arrays matching in whenIgnoringPaths
  • Version 3.2.6 skipped due tue a mistake

3.2.5 (2024-02-20)

  • #483 Fix JsonPath arrays matching in whenIgnoringPaths
  • Dependency updates

3.2.4 (2024-02-05)

  • Dependency updates
  • Version 3.2.3 skipped due to release issues

3.2.2 (2023-09-14)

  • Fix Kotest module dependencies

3.2.1 (2023-09-14)

  • Support for Kotest
  • Dependency upgrades

3.2.0

  • Skipped for technical reasons

3.1.0 (2023-09-12)

  • Support for custom matchers in Spring assertions
  • Dependency upgrades

3.0.0 (2023-07-05)

  • Requires Java 17
  • Requires Spring 5.2 (when used with Spring)
  • Options class hidden
  • Deprecated methods and classes removed
  • Dependency upgrades

2.38.0 (2023-05-22)

  • Support for NumberComparator
  • Dependency updates

2.37.0 (2023-03-23)

  • Make custom matcher regexp DOTALL (#617)
  • Dependency updates

2.36.1 (2023-01-29)

  • #595 Fix slf4j dependency
  • Dependency updates

2.36.0 (2022-10-05)

  • Support for node method in JsonMapAssert #560
  • Fixed number parsing in Jackson, so it works as intended (see #564 for details)
  • Dependency updates

2.35.0 (2022-05-06)

  • Special handling of numeric values in containsEntry #512
  • Dependency updates

2.34.0 (2022-04-12)

  • Prevent re-parsing of a value #502
  • Dependency updates

2.33.0 (2022-04-02)

  • Fixed #493 comparison of Tuples from extracting function

2.32.0 (2022-02-17)

  • Fixed #474 ClassCastException in isArray()

2.31.0 (2022-02-07)

  • Replaced JsonObjectAssert by JsonAssert

2.30.0 (2022-02-06)

  • Parent type of JsonObjectAssert changed to AbstractAssert

2.29.0 (2022-02-05)

  • #465 fixed assertion on array of objects. May introduce some backward incompatibility when using isArray().element(i).
  • Dependency updates

2.28.0

  • Automatically register available Jackson 2 modules
  • Dependency updates

2.27.0

  • Made compatible with AssertJ 3.20.x - due to braking changes in AssertJ this version also requires AssertJ 3.20.x and higher.

2.26.0

  • Fixed containsEntries in AssertJ object assert. This required to change the return type of isObject() method which may be an incompatible change for tests which store the result in a variable.

2.25.0

  • Hamcrest matcher made compatible with Rest Assured #338
  • Various library upgrades

2.24.0

  • Fix OSGi configuration
  • AssertJ updated to 3.19.0

2.23.0

  • Better error message for multiple matches in isAbsent check
  • Various library upgrades

2.22.1

  • Better exception message in case of JSON that can not be parsed

2.22.0

  • Support for Spring WebTestClient

2.21.0

  • Fixed Kotlin AssertJ bundle #299

2.20.0

  • assertThatJson accepts null as the actual value

2.19.0

  • opentest4j made optional #276
  • updated all dependencies

2.18.1

  • Fix multiple when method application #234

2.18.0

  • Support for URI assertions

2.17.0

  • Do not append tolerance with zero value to diff message (thanks @valfirst)

2.16.2

  • Fix regex issues on older Androids #227 (thanks @Sirrah)

2.16.1

  • Add missing Kotlin classes to distribution Jars

2.16.0

  • Kotlin DSL for AssertJ API

2.15.0

  • Spring DSL Koltin support
  • JUnit upgraded to 5.6.0

2.14.0

  • Allow differentiating between number and integer

2.13.1

  • Fix Jackson2NodeFactory thread safety issue in usage of ServiceLoader (thanks @cnauroth)

2.13.0

  • Recompiled with AssertJ 3.15.0 to fix #216
  • (Not)Null annotations added
  • Spring dependency updated to 5.2.3.RELEASE

2.12.0

  • Updated dependencies
  • Jackson node is not reparsed when compared #214

2.11.1

  • Parse content as UTF-8 in Spring MVC test if not specified otherwise #212

2.11.0

  • Fix Kotlin 'Inaccessible type' warning in when-path (@Vladiatro)
  • Load resources as UTF-8 (@bencampion)

2.10.0

  • Support for PathOptions
  • AssertJ - support for chaining assertions in the same root
  • Support for json-path in AssertJ whenIgnoringPaths

2.9.0

  • Hamcrest upgraded to 2.1
  • AssertJ dependency upgraded to 3.12.3 (requires AssertJ > 3.10.0)

2.8.1

  • hamcrest-core dependency marked as required

2.8.0

  • #185 JsonUnitRequestMatchers for client-side REST testing
  • Support for array (non)emptiness in Fluent assert

2.7.0

  • Support for Johnzon (requires 1.1.12) (thanks to elexx)

2.6.3

  • Ignoring paths even when present in expected value #182

2.6.2

  • Fixed AssertionErrors messages in MultipleFailuresError #181

2.6.1

  • Path with backspaces matching fixed #176

2.6.0

  • ${json-unit.ignore-elements} introduced

2.5.1

  • Array comparison optimization

2.5.0

  • Fix bug and performance issues in array comparison
  • Performance optimizations

2.4.0

  • Introduced JsonAssertions.value()
  • Fixed AssertJ withFailMessage

2.3.0

  • Support for Jackson 2 ObjectMapper customization
  • Some AbstractObjectAssert marked as unsupported

2.2.0

  • Using opentest4j
  • Refactored exception reporting

2.1.1

  • Better exception reporting
  • Fixed invalid Automatic-Module-Name

2.0.3

  • Fixed missing node handling with JsonPath
  • Fixed some complex AsserJ comaprisons

2.0.2

  • Fixed #144 (AssertJ object handling)

2.0.1

  • Support for # instead of $ in placeholders

2.0.0.RC5

  • More expressive Spring assertions (isNull, isNotNull, isTrue, isFalse)

2.0.0.RC4

  • AssertJ - fix bug with '%' in error message
  • Removed support for Jackson 1

2.0.0.RC3

  • Support for and() in AssertJ assert
  • asNumber() in AssertJ added
  • Allow description before inPath() in AssertJ

2.0.0.RC2

  • Fixed JsonPath bug #132
  • Fixed AssertJ number comparison with Jackson 2 #130
  • Fixed AssertJ asString() #131

2.0.0.RC1

  • Depends on Java 8
  • Some deprecated APis removed
  • Introduces AssertJ module
  • Introduces JsonPath module

Please do not hesitate to report issues.

1.31.0

  • Introduced DifferenceContext into DifferenceListener

1.30.0

  • Introduced DifferenceListener
  • Array comparison reports extra/missing elements when comparing with array order preserved.

1.29.1

  • Fixed error in JsonFluentAssert.ofLength error message
  • Fixed matcher handling when comparing arrays #111

1.29.0

  • [*] placeholder works even when ignoring array order

1.28.2

  • Fixing matcher pattern

1.28.1

  • Fixing NPE when accessing element of nonexistent array

1.28.0

  • Support for [*] placeholder in ignored path

1.27.0

  • Better array comparison and error messages

1.26.0

  • IDE friendly error messages
  • isStringEqualTo is chainable (thanks to @gsson)
  • Dropped support of Java 5
  • Automatic module names added

1.25.1

  • Support for Jackson BinaryNode

1.25.0

  • Support for ignoring paths whenIgnoringPaths()

1.24.0

  • Support for parametres in custom matchers ${json-unit.matches:matcherName}param

1.23.0

  • Support for custom matchers ${json-unit.matches:matcherName}

1.22.0

  • Support for Moshi

1.21.0

  • Better diff reporting for unordered arrays with single difference

1.20.0

  • Negative array indexes added (thanks roxspring)

1.19.0

  • isArray().thatContains(...) fluent assert added

1.18.0

  • Resource reading helper added

1.17.0

  • System property to specify JSON libraries to be used

1.16.1

  • Array pattern accepts non-word characters

1.16.0

  • isAbsent and isPresent checks take TREAT_NULL_AS_ABSENT into account

1.15.0

  • Dependency on slf4j made optional

1.14.1

  • Preferring org.json library to process JSONArray

1.14.0

  • Support for org.json library
  • Fix: Element out of array bounds is treated as missing

1.13.0

  • Support for any-* placeholders

1.12.1

  • Single quote values in expected String allowed

1.12.0

  • Lenient parsing of expected values

1.11.0

  • Option setting methods made deprecated if called after assertion in JsonFluentAssert
  • JsonFluentAssert constructors made private. Please file an issue if you need them.

1.10.0

  • Added support for IGNORING_EXTRA_ARRAY_ITEMS

1.9.0

  • Made compatible with Jackson 1.4

1.8.0

  • OSGi support thanks to @amergey

1.7.0

  • Support for Spring MVC tests assertions

1.6.1

  • Gson nodes are not reconverted

1.6.0

  • Added support for Hamcrest matchers

1.5.6

  • Fixed handling of empty value in the expected parameter

1.5.5

  • Support for dot in node name

1.5.4

  • Added isObject method to fluent assertions

1.5.3

  • Jackson 1 is preferred if the serialized class contains Jackson1 annotation

1.5.2

  • Added support for regular expressions

1.5.1

  • isStringEqualTo() added to fluent assertions
  • isArray added to fluent assertions

1.5.0

  • One runtime now supports Jackson 1.x, Jackson 2.x and Gson
  • Internal JsonUnit class changed in backwards incompatible way

1.3.0 + 0.3.0

  • Options renamed
  • assertJsonNot* asserts added
  • Support for online configuration in Hamcrest and standard asserts added

1.2.0 + 0.2.0

  • Error messages changed a bit when comparing structures
  • Refactoring of internal classes
  • Support for ignoring array order
  • Support for ignoring values
  • Support for ignoring extra fields

1.1.6 + 0.1.6

  • Treat null as absent added

1.1.5 + 0.1.5

  • Absence/presence tests added

1.1.4 + 0.1.4

  • Path to array in root fixed

1.1.3 + 0.1.3

  • Numeric comparison tolerance added

1.1.2 + 0.1.2

  • jsonStringEquals and jsonStringPartEquals added

1.1.1 + 0.1.1

  • Generics in JsonMatchers fixed

1.1.0 + 0.1.0

  • Simplified API
  • Invalid JSONs in String comparison quoted
  • Runtime incompatible (compile-time compatible) changes

1.0.0

  • Switched to Jackson 2.x
  • Fluent JsonAssert renamed to JsonFluentAssert

0.0.16

  • Fluent assertions made framework independent.

0.0.15

  • Switched from FEST to AssertJ

0.0.14

  • Modules refactored
  • Added support for FEST assert

0.0.13

  • Logging categories changed

0.0.12

  • Added logging

0.0.11

  • Ignore placeholder "${json-unit.ignore}" added

0.0.10

  • Text differences are closed in quotes

0.0.9

  • Matchers added

0.0.7

  • Made Java 5 compatible

0.0.6

  • assertJsonPartStructureEquals added

0.0.5

  • assertJsonPartEquals added

0.0.4

  • Better error messages in case of different types

0.0.3

  • Support for array types and other oddities in root

0.0.2

  • Support for nulls

jsonunit's People

Contributors

amergey avatar andrewscode avatar based2 avatar cnauroth avatar dependabot[bot] avatar edbarvinsky avatar egga-zz avatar ericlemerdy avatar fegbers avatar japudcret avatar joeltucci avatar joergsiebahn avatar keers avatar leonard84 avatar liry avatar lukas-krecan avatar lukas-krecan-gdc avatar lukas-krecan-lt avatar micahzoltu avatar pradzins avatar reftel avatar rotty3000 avatar sirrah avatar snyk-bot avatar sullis avatar valfirst avatar viclovsky avatar vladiatro avatar xp-vit avatar yayayya-boop avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jsonunit's Issues

Comparison of jsons (with tolerance) fails for numbers, when any option is provided

Passes:
JsonAssert.setTolerance(0.01);
assertJsonEquals("{"test":1}", "{"test":1.009}");

Passes:
assertJsonEquals("{"test":1}", "{"test":1,"extra":2323}", when(IGNORING_EXTRA_FIELDS));

Fails:
JsonAssert.setTolerance(0.01);
assertJsonEquals("{"test":1}", "{"test":1.009}", when(IGNORING_EXTRA_FIELDS));

Combining withTolerance and when Option fails.

JsonFluentAssert#isAbsent is not honoring TREATING_NULL_AS_ABSENT

Hello,
I have a JSON which doesn't have root node and somehow TREATING_NULL_AS_ABSENT is not giving any affect to the result, below is the code:

String json = "{\"a\":1, \"b\": null}";
JsonFluentAssert jsonAssert = JsonFluentAssert.assertThatJson(JsonUtils.convertToJson(json, "actual"));
jsonAssert.when(Option.TREATING_NULL_AS_ABSENT).node("b").isAbsent();

What could be wrong here?

Thanks!

Include it as a jar

Hi I wish to include JsonUnit for Json comparison in a in-house scripting language used for automated testing; I am trying to build it using 'mvn install' but it gets stuck and does not complete.

Can you share correct steps for it or share a already built jar.

Can't compare String node with Integer Value

Hi,

I am currently trying to compare a node, which has an String value, that only contains numbers, for example:

JsonFluentAssert.assertThatJson("{"test": "2"}").node("test").isEqualTo("2");

I can not find a way to get this running - it always says, that '2' is expected but it got ''"2"'. It seems like JsonUnit casts the "2" to an int, and is therefore not capable of checking the value correctly. Is this right, or is there another way of comparing string node values?

JsonUtils.arrayPattern is too strict

I am trying to test some JSON-LD output and I am getting caught up on the following JSON:

{
  "@id" : "urn:uuid:50aa37c0-eef0-4d72-9f32-17ebbcf17c10",
  "@graph" : [
    { "foo" : "bar" }
  ]
}

Using the Fluent assertions, the following fails:

assertThatJson(json).node("@graph[0].foo").isEqualTo("bar");

Because the string "@graph[0]" does not match the array pattern (currently (\w*)\[(\d+)\]), in this case the "@" character is not a word character.

Technically, there isn't much that JSON doesn't allow in a name: it is just a string so pretty much any non-control character goes. Edge cases involving the syntax aside (i.e. names that contain square brackets), and borrowing heavily from here I came up with the following (absolutely terrifying) regex which seems to work:

Pattern.compile("((?:(?:[^\"\\\\])|(?:\\\\[\"\\\\bfnrt\\/])|(?:\\\\u\\{XDigit}{4}))*)\\[(\\d+)\\]");

`gson`: comparing two strings may fail due to lazy number parsing

When using gson as the JSON parser dependency, the following test fails despite that it shouldn't:

assertJsonEquals("{\"foo\": 1.0}", "{\"foo\": 1.00}")

This is because gson parser parses numbers lazily: when parsing, it internally stores a string. Then, when serializing, the same string is reused. See the LazilyParsedNumber class.

Switching to moshi helps.

Simpler JSON string literals

Hello

I was wondering if there is a possibility to implement less strict definitions of JSON literals for expected value.

For example, to reduce this:
assertThatJson(responseBody).isEqualTo("{"property1":"value1", "property2":{["item1", "item2"]}}");

To this:
assertThatJson(responseBody).isEqualTo("{property1:'value1', property2:{['item1', 'item2']}}");

More or less, to allow syntax closer to the way it is written in JavaScript, in order to reduce the number of escaped double quotes by using single quotes for strings, and omitting them for field names.

The reason for this is to improve readability. It's hard to see the actual expected JSON when there is so many escaped quotes. These examples are short, but in a real world scenario JSONs are usually much longer.

An alternative approach could be to store expected JSONs as files and load them, but that way expected values are far away from the test, again hurting readability.

custom matcher for embedded json

I am facing issue while passing jsonObject as parameter . It is considering it as a whole string and not as a argument as can be checked in attached screenshot .
actual vs expected

String expected = "{"response":{'${json-unit.matches:containsJSON}'"+jsonObject+"}}"; //Not working
assertJsonEquals(expected, actual, JsonAssert.withMatcher("containsJSON", embeddedJsonMatcher));

Check this
json_matcher

Hamcrest-Style Array Tests

Is it possible to use Hamcrest-Style tests for testing an array?

While things like

JsonFluentAssert.assertThatJson(runningJobs).isArray().ofLength(2);

work fine, I can't find a way to do things like this with hamcrest-style matchers.

And is there any way to test weather an array contains a certain node?

For example, if I've got the JSON [{"a": 7},8], can I make something like:

JsonFluentAssert.assertThatJson(runningJobs).node("{\"a\": 7}").isPresent();

to test weather the node is present in an Array?

Timestamp comparison with tolerance?

I was wondering if there is a way to specify tolerance for timestamp comparisons?

Since my tests run in realtime, I would know the time that should be output to a few seconds, but not an exact value. Currently that forces me to regex the whole timestamp field.

I was thinking something like {json-unit.timestamp:[period]} could specify that this is a timestamp field and to compare it with a tolerance of [period].

Request: fluent matcher for non-existence of node

I couldn't find a way to assert the non-existence of a node. It would be very useful to have assertions something like this:

  assertThatJson(json).node("user.password").doesNotExist();

The assertion should succeed if the JSON does not contain a node at the given path, and should fail if the JSON does contain such a node, regardless of the value.

Thanks!

Feature Request: match node with any Matcher

Could you please add support for applying generic Matchers to JSON nodes? For example, make this test work:

import static net.javacrumbs.jsonunit.fluent.JsonFluentAssert.assertThatJson;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.lessThan;
import static org.hamcrest.core.IsCollectionContaining.hasItem;
import static org.junit.Assert.assertThat;

import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;

public class JsonFluentFeatureRequest {
    private String json;

    @Before
    public void init() {
        json = "{ 'num': 40, 'messages': [ 'hello', 'world' ] }".replace('\'', '"');
    }

    /** The matchers used in the other tests, without JsonUnit. */
    @Test
    public void testBasicMatchers() {
        assertThat(40, allOf(greaterThanOrEqualTo(20), lessThan(100)));
        assertThat(Arrays.asList("hello", "world"), hasItem("world"));
    }

    @Test
    public void testNodeMatchesRegex() {
        assertThatJson(json).node("messages").matches(hasItem("world"));
    }

    @Test
    public void testNodeMatchesIntegerRange() {
        assertThatJson(json).node("num").matches(allOf(greaterThanOrEqualTo(20), lessThan(100)));
    }
}

Thanks!

Diff pattern lost when ignoring array order

Hello

I'm having a small issue while comparing two json ;

Actually i'm used to catch the assertion message in this pattern : Expected <> but was <>
When i'm using IGNORING_ARRAY_ORDER, I catch an array excpetion containing the whole array, and not only the difference fields.

Is there a way to keep the same pattern and using ignoring array order

Thanks

Force to use GSON always

I have bigger project and in its transitive dependencies Jackson2 can be find. But I would like to use Gson in tests. Unfortunately the algorithm is:

    for (int i = 0; i < factories.size(); i++) {
        NodeFactory factory = factories.get(i);
        if (isLastFactory(i) || factory.isPreferredFor(source)) {
            return factory.convertToNode(source, label, lenient);
        }
    }

where the last factory is always Jackson2.
Is there any way to configure JsonUnit to force it to use Gson? Or can it be added?

Difference detail is not given out if compare 2 json using option ignore_array_order

String exp = "{"dataStreamsCount":1,"dataStreams":[{"device":"testDevice_single_boolean_sensors","sensor":"sensor_boolean_1","dataPointsCount":20,"dataPoints":[{"iso":"2011-12-31T17:01:01.001Z","value":"true"},{"iso":"2011-12-31T17:01:01.002Z","value":"false"},{"iso":"2011-12-31T17:01:01.003Z","value":"true"},{"iso":"2011-12-31T17:01:01.004Z","value":"false"},{"iso":"2011-12-31T17:01:01.005Z","value":"true"},{"iso":"2011-12-31T17:01:01.007Z","value":"false"},{"iso":"2011-12-31T17:01:01.008Z","value":"true"},{"iso":"2011-12-31T17:01:01.009Z","value":"false"},{"iso":"2011-12-31T17:01:01.011Z","value":"true"},{"iso":"2011-12-31T17:01:01.012Z","value":"false"},{"iso":"2011-12-31T17:01:01.013Z","value":"true"},{"iso":"2011-12-31T17:01:01.014Z","value":"false"},{"iso":"2011-12-31T17:01:01.016Z","value":"true"},{"iso":"2011-12-31T17:01:01.017Z","value":"false"},{"iso":"2011-12-31T17:01:01.019Z","value":"true"},{"iso":"2011-12-31T17:01:01.020Z","value":"false"},{"iso":"2011-12-31T17:01:01.021Z","value":"true"},{"iso":"2011-12-31T17:01:01.022Z","value":"false"},{"iso":"2011-12-31T17:01:01.023Z","value":"true"},{"iso":"2011-12-31T17:01:01.024Z","value":"false"}]}]}";

String actual = "{"dataStreamsCount":1,"dataStreams":[{"device":"testDevice_single_boolean_sensors","sensor":"sensor_boolean_1","dataPointsCount":20,"dataPoints":[{"value":"true","iso":"2011-12-31T17:01:01.001Z"},{"value":"false","iso":"2011-12-31T17:01:01.002Z"},{"value":"true","iso":"2011-12-31T17:01:01.003Z"},{"value":"false","iso":"2011-12-31T17:01:01.004Z"},{"value":"false","iso":"2011-12-31T17:01:01.005Z"},{"value":"false","iso":"2011-12-31T17:01:01.007Z"},{"value":"true","iso":"2011-12-31T17:01:01.008Z"},{"value":"false","iso":"2011-12-31T17:01:01.009Z"},{"value":"false","iso":"2011-12-31T17:01:01.011Z"},{"value":"false","iso":"2011-12-31T17:01:01.012Z"},{"value":"false","iso":"2011-12-31T17:01:01.013Z"},{"value":"false","iso":"2011-12-31T17:01:01.014Z"},{"value":"true","iso":"2011-12-31T17:01:01.016Z"},{"value":"false","iso":"2011-12-31T17:01:01.017Z"},{"value":"false","iso":"2011-12-31T17:01:01.019Z"},{"value":"false","iso":"2011-12-31T17:01:01.020Z"},{"value":"true","iso":"2011-12-31T17:01:01.021Z"},{"value":"false","iso":"2011-12-31T17:01:01.022Z"},{"value":"false","iso":"2011-12-31T17:01:01.023Z"},{"value":"false","iso":"2011-12-31T17:01:01.024Z"}]}]}";

assertJsonEquals(exp, actual,JsonAssert.when(Option.IGNORING_ARRAY_ORDER));
assertJsonEquals(exp, actual);

compare above 2 output. Compare method 1 will not give difference detail, but compare method 2 will do.

Add OSGI Manifest headers

Hello,

Currently JsonUnit cannot be used in OSGI environment, OSGI Manifest headers are missing.
There is a maven plugin allowing to achieve that quite easilly

I will create a pull request to propose a fix about that

Failing test when json has a whitespace difference in the array

Hello,

I have a test like this:

@Test
public void failure_on_whitespace() {
    List<String> actual = Lists.newArrayList("{\"a\":1}", "{\"a\" :2}");
    List<String> expected = Lists.newArrayList("{\"a\":1}", "{\"a\":2}");

    assertThatJson(actual).when(IGNORING_ARRAY_ORDER).isEqualTo(expected);
}

The 2 json are the same, but the second one in the first List has an extra whitespace.
When I run the test, it is failing:

15:02:13.922 [main] DEBUG n.j.jsonunit.difference.diff - JSON documents are different:
Different value found in node "". Expected "{"a":2}", got "{"a" :2}".
15:02:13.926 [main] DEBUG n.j.jsonunit.difference.values - Comparing expected:
"{\"a\":2}"
------------
with actual:
"{\"a\" :2}"

15:02:13.929 [main] DEBUG n.j.jsonunit.difference.diff - JSON documents are different:
Array "" has different content. Missing values ["{\"a\":2}"], extra values ["{\"a\" :2}"]
15:02:13.929 [main] DEBUG n.j.jsonunit.difference.values - Comparing expected:
["{\"a\":1}","{\"a\":2}"]
------------
with actual:
["{\"a\":1}","{\"a\" :2}"]

15:02:13.929 [main] DEBUG n.j.jsonunit.difference.diff - JSON documents are different:
Array "" has different content. Missing values ["{\"a\":2}"], extra values ["{\"a\" :2}"]
15:02:13.929 [main] DEBUG n.j.jsonunit.difference.values - Comparing expected:
["{\"a\":1}","{\"a\":2}"]
------------
with actual:
["{\"a\":1}","{\"a\" :2}"]


java.lang.AssertionError: JSON documents are different:
Array "" has different content. Missing values ["{\"a\":2}"], extra values ["{\"a\" :2}"]

In the README you state that "When the values are compared, order of elements and whitespaces are ignored".
If I'm trying to compare two strings, not arrays, then it's working fine, e.g.:

@Test
public void passed_when_comparing_simple_strings() {
    String actual = "{\"a\" :2}";
    String expected = "{\"a\":2}";

    assertThatJson(actual).isEqualTo(expected);
}

Tried with the json-unit-fluent library, version 1.12.1.

java version "1.8.0_77"
Java(TM) SE Runtime Environment (build 1.8.0_77-b03)
Java HotSpot(TM) 64-Bit Server VM (build 25.77-b03, mixed mode)

Could you check this issue?

Regards,
Norbert

Allow for options after assertion (json-unit-fluent)

I have a specific use case where I write my assertions like so: assertThatJson(actual).isEqualTo(expected).

However when using the TREATING_NULL_AS_ABSENT option in conjunction with the format I use, I end up with a failing test because (assumption here) the option is applied before the assertion. So in order for me to get a passing test, I have to switch it like so: assertThatJson(expected).when(TREATING_NULL_AS_ABSENT).isEqualTo(actual).

Note a huge deal but I do wish to keep my format/ordering consistent across the board if possible.

Fluent Matcher for Array at the Document Root

I like JSONUnit, and I've been successful with it until now. I need help with a Fluent matcher for a JSON document that has an array as the root. Here's an example of what I'm trying to do:

assertThatJson("[ {"myId": 0 }, {"myId": 1 }]").node("[0].myId").isEqualTo("0");

So, the JSON document would be:
[
{ "myId" : 0 },
{ "myId" : 1 }
]

I checked this on JSONLint, and it's valid.

So, what expression should I use for node() ?

Thanks.

Tom

isEqualsTo with String node

May I miss something but when trying the following assertion:

JsonNode jsonNode = new ObjectMapper().readTree("{\"meta\":{\"version\":\"1.0\"}}");
assertThatJson(jsonNode).node("meta.version").isEqualTo("1.0");

I had the following error Different value found in node "meta.version". Expected '1.0', got '"1.0"'.

I think it's because you are using .toString() instead of .asText().

Asserting with rest-assured

Hi this isn't an issue with jsonUnit more with my understanding of how it is suppose to work.

I'm currently using rest assured and Json-unit to assert a local json file against the requested rest assured response. I currently have a before class method with my base uri. I am struggling with the test. I know I'm way off at the moment. I'm struggling with the json-unit documentation. Do I need to input a file first? I'm not really sure I follow the documentation that well? Im definitely missing some pieces. Would anyone be able to point me in the right direction?

@Test     
public void ApiaryTest1() throws Exception {          

when()                  
.get("/test")                
 .then()                 
.statusCode(200);  
// compares two JSON documents        
 assertJsonEquals("expected/test.json", "http://apiary/test");
}

JsonMatchers not doing the correct comparison with DateTime objects

Hi,

I'm using jsonPartEquals from JsonMatchers to do a validation for a DateTime object as a String but the Matcher is not doing the correct comparison. It's breaking down the DateTime object into individual units and as a result, the assertion is failing. Any advice on this issue? Reproducible pasted below.

String my_mock_response = "{\"mock_response\":{\"date\":\"1988-06-22T00:00:00.000Z\"}}";
Response actualResponse = Mockito.mock(Response.class);
when(actualResponse.readEntity(String.class)).thenReturn(my_mock_response);
when(actualResponse.getMediaType()).thenReturn(MediaType.APPLICATION_JSON_TYPE);
        
DateOfEvent date = DateOfEventData.dateOfEvent(EventType.BIRTH, "1988-06-22T00:00:00.000Z");
assertThat(actualResponse, HasJsonNodeWithValueMatcher.hasJsonPartEquals("mock_response.date", date.getEventDate()));

gives me this error:

Expected: has value 1988-06-22T00:00:00.000Z in "mock_response.date"
     but: Response JSON JSON documents are different:
Different value found in node "mock_response.date". Expected '{"year":1988,"dayOfMonth":22,"dayOfWeek":3,"era":1,"dayOfYear":174,"weekyear":1988,"weekOfWeekyear":25,"monthOfYear":6,"yearOfEra":1988,"yearOfCentury":88,"centuryOfEra":19,"millisOfSecond":0,"millisOfDay":0,"secondOfMinute":0,"secondOfDay":0,"minuteOfHour":0,"minuteOfDay":0,"hourOfDay":0,"zone":{"fixed":true,"id":"UTC"},"millis":582940800000,"chronology":{"zone":{"fixed":true,"id":"UTC"}},"afterNow":false,"beforeNow":true,"equalNow":false}', got '"1988-06-22T00:00:00.000Z"'.

Allow selection of Jackson 2 over Jackson 1 if both are in classpath

Currently not possible to force usage of Jackson 2 over Jackson 1 if both are in the classpath.

This is a problem in a legacy project that has dependency to older version of Jackson 1 via a third party component.

It is possible to exclude version 1 from classpath in Maven surefire/failsafe but this is not possible in Eclipse.

an extension point similar to json-unit.regex

Hi,

I have a use case where I'd like to capture data during the comparison process, and store it into a variable. One way to do that would be to make an expression like so:

${json-unit.capture}variable-name

Adding this directly to json-unit would not make a lot of sense as it is too specific to my needs.

However, I was thinking possibly this could be accommodated as a generalisation of json-unit.regex, since they both take the same form:

${json-unit.<name>}<value>

Would you consider a customisation point that allows the creation of expressions like so?

Thanks

Facing issues when comparing jsons with Arrays

java.lang.NoSuchMethodError: org.json.JSONArray.iterator()Ljava/util/Iterator;
at net.javacrumbs.jsonunit.core.internal.JsonOrgNodeFactory$JSONArrayNode.arrayElements(JsonOrgNodeFactory.java:188)
at net.javacrumbs.jsonunit.core.internal.Diff.compareArrayNodes(Diff.java:317)
at net.javacrumbs.jsonunit.core.internal.Diff.compareNodes(Diff.java:229)
at net.javacrumbs.jsonunit.core.internal.Diff.compareObjectNodes(Diff.java:120)
at net.javacrumbs.jsonunit.core.internal.Diff.compareNodes(Diff.java:226)
at net.javacrumbs.jsonunit.core.internal.Diff.compare(Diff.java:82)
at net.javacrumbs.jsonunit.core.internal.Diff.similar(Diff.java:454)
at net.javacrumbs.jsonunit.JsonAssert.assertJsonPartEquals(JsonAssert.java:80)
at net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals(JsonAssert.java:65)
at net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals(JsonAssert.java:58)

Is there a particular json jar dependecy? The one I am using doesnt have iterator method

Json diff with COMPARING_ONLY_STRUCTURE

Hello. Equals 2 json files with COMPARING_ONLY_STRUCTURE not include sub fields. For example:
{
"returnDocumentId": 10209,
"returnDocumentNum": null,
"returnDocumentType": {
"returnDocumentTypeId": 1000,
"name": "test1"
}
}

and

{
"returnDocumentId": 10209,
"returnDocumentNum": null,
"returnDocumentType": null
}

If they was equals with COMPARING_ONLY_STRUCTURE option, result is succsess. But expected fail result because "returnDocumentType" node include 2 fields "returnDocumentTypeId" and "name".

isObject for json-unit-fluent

Hello

Could be cool to have a method to check that a node is a Json Object :

assertThatJson(json)
                .node("toto")
                .isObject()

what do you think ?

I try to fork the repo to send you a pull request but when i fork your repo, the code is not update to date. (i haven't the method isArray for example).

Update Jackson to 2.x ?

Since most project like Spring 4.0 had updated to Jackson 2.x, can json-unit also do that?

JsonAssert.assertJsonStructureEquals succeeds when comparing against null as actual value

When comparing an expected structure against null the assertion passes. This seems like a false positive to me.

import org.junit.Test;
import static net.javacrumbs.jsonunit.JsonAssert.assertJsonStructureEquals;

public class MyTestCase {

    @Test
    public void myTest() {
        // This assertion will pass
        assertJsonStructureEquals(
            "{" +
                "  \"key\": \"value\"," +
                "  \"other\": \"another\"" +
                "}",
            null
        );
    }
}

assertJsonStructureEquals doesn't compare entire document

assertJsonStructureEquals describes comparing structure of json but it's only comparing the top level elements. To me, assertJsonStructureEquals should fail for these 2 strings:

{"test": 3}
{"test": {"inner": 5}}

It would be better if assertJsonStructureEquals just compares types and not the actual values. This can be achieved by simply change the valueDifferenceFound to structureDifferenceFound.

        if (!expectedNodeType.equals(actualNodeType)) {
            structureDifferenceFound("Different value found in node \"%s\". Expected '%s', got '%s'.", fieldPath, expectedNode, actualNode);
        } else {

Is it possible to compare structure without taken into account Fields order(include array), new fields

Hi

My use case is this one:
I want to compare the structure of 2 json object/string in order to detect break into an API.
Having Expected json as E and another json value as V:

I would like to have a comparator which success when

  • Fields order into E and V are different
  • No matter of field array ordering
  • If V contains new field(s) that are not present into E

And failed when

  • E contains field(s) that are no more present into V
  • Field is present into the both but type is different from E to V

Maybe I'm wrong but after reading the javadoc, it seems not implemented in the current version ?
If yes, does it make sense for you to add this feature ?

Thx
Christophe

Json diff

Is there any way to see the json diff, exactly as when we assert strings? Using ordinary assertions on IntelliJ allows me to compare two jsons when an assertion fails. It's much more efficient for identifying the differences in long json files.

Regex-compare number values

First of all, thanks for this great tool!

It's currently not possible to compare numbers with regex values, like this -- as the types don't match:

assertThat("{\"test\":12}", jsonEquals("{\"test\":\"${json-unit.regex}[0-9]+\"}"));

Is it possible to enhance the library to give a more flexible comparison while testing one big JSON at once? IMO it is very productive to just having large JSON strings (e.g. in a file) with the ${json-unit.*} enhancement for everything which is not fix. That's why I like the idea of these 'variables' very much.

Maybe one of these proposals (which would change the compared type then) -- you certainly have a better view which would fit in the current overall picture:

${json-unit.number}[0-9]+
${json-unit.regex.number}[0-9]+
${json-unit.number}${json-unit.regex}[0-9]+

WDYT?

Comparing structure does not fail when node is applied.

This test fails :
(in AbstractJsonFluentAssertTest)

@Test
public void testDifferentStructureWithPath() {
    try {
        assertThatJson("{\"root\":{\"test\":1}}").node("root")
                .hasSameStructureAs("it should fail");
        expectException();
    } catch (AssertionError e) {
        assertEquals("JSON documents are different:\n"
                + "Different value found in node \"root\". Expected '\"it should fail\"', got '{\"test\":1}'.\n",
                e.getMessage());
    }
}

Is this a bug or a bad usage ?

JSONArray of JSONObjects

Hi,

Is there a way to assert JSONArray of three JSONObjects? Server returns the objects in different order each time and IGNORING_ARRAY_ORDER doesn't seem to help here.

Thanks

IGNORING_EXTRA_FIELDS option not working for Fluent assertions

I am using 1.10 version of json-unit-fluent. On running with following JSON values, I am getting the message :-

FAILED: compareJSONFiles
java.lang.AssertionError: JSON documents are different:
Different keys found in node "data". Expected [monitortrendingentity], got [company, monitortrendingentity]. Extra: "data.company"

Please look into this.

JsonFluentAssert.assertThatJson("{ "status": "success", "message": "spiking topic data populated successfully.", "data": { "monitortrendingentity": [ { "companyid": 0 } ], "company": { "ticker": "ge" } }, "statuscode": "request_success"}").isEqualTo("{ "status": "success", "statuscode": "request_success", "message": "spiking topic data populated successfully.", "data": { "monitortrendingentity": [ { "companyid": 0 } ] } }").when(Option.IGNORING_ARRAY_ORDER,Option.IGNORING_EXTRA_FIELDS,Option.IGNORING_EXTRA_ARRAY_ITEMS);

Type and size comparaison

Do you plan to add type & size comparaison like following

assertThatJson(json).node('elements').isPresent().isArray().size(12);

Exception when using org.json.JSONObject object

@lukas-krecan @lukas-krecan-gdc
Getting below exception

Exception in thread "main" java.lang.IllegalArgumentException: No serializer found for class org.json.JSONObject and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)

When using like

JSONObject object = new JSONObject();
object.put("abx","xyz");
JSONObject object1 = new JSONObject();
object1.put("qwe","rty");
CustomMatcher.assertThat(object, JsonMatchers.jsonEquals(object1));

Option to ignore order in map should be available

I am getting a map which comes in different order in each request. Is there any way to ignore order of map? The below screenshot shows the response from two json where tree_topics comes at order one while in other hit it comes second. Please help

image

Can't catch any assertions

As I'm comparing tons of Json (rest response and standard files), I want to do the assertions, catch the exception (if exist) and continue my code.
I'm using groovy
Here's my code snippet

try {
	assertJsonEquals(ExpectedResponse, ActualResponse)
}
catch (Exception e) {
	log.info(e)
}

The code can't catch the result of the assertions, in fact I want to catch it in a String then parse it (to separate errors found)

Thanks for this amazing library :)

Cheers

JsonMatchers not doing the correct comparison with DateTime objects

Hi,

I'm using jsonPartEquals from JsonMatchers to do a validation for a DateTime object as a String but the Matcher is not doing the correct comparison. It's breaking down the DateTime object into individual units and as a result, the assertion is failing. Any advice on this issue? Reproducible pasted below.

import static org.hamcrest.MatcherAssert.assertThat;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import net.javacrumbs.jsonunit.JsonMatchers;

String my_mock_response = "{\"mock_response\":{\"date\":\"1988-06-22T00:00:00.000Z\"}}";

DateTime date = new DateTime("1988-06-22T00:00:00.000Z", DateTimeZone.UTC);
assertThat(my_mock_response, JsonMatchers.jsonPartEquals("mock_response.date", date));

Error message I get:

Expected: 1988-06-21T19:00:00.000-05:00 in "mock_response.date"
     but: JSON documents are different:
Different value found in node "mock_response.date". Expected '{"weekyear":1988,"weekOfWeekyear":25,"monthOfYear":6,"yearOfEra":1988,"yearOfCentury":88,"centuryOfEra":19,"millisOfSecond":0,"millisOfDay":68400000,"secondOfMinute":0,"secondOfDay":68400,"minuteOfHour":0,"minuteOfDay":1140,"hourOfDay":19,"year":1988,"dayOfMonth":21,"dayOfWeek":2,"era":1,"dayOfYear":173,"chronology":{"zone":{"fixed":false,"uncachedZone":{"cachable":true,"fixed":false,"id":"America/Chicago"},"id":"America/Chicago"}},"zone":{"fixed":false,"uncachedZone":{"cachable":true,"fixed":false,"id":"America/Chicago"},"id":"America/Chicago"},"millis":582940800000,"afterNow":false,"beforeNow":true,"equalNow":false}', got '"1988-06-22T00:00:00.000Z"'.

Compare with ignore path

Hello,

I have a some hundreds of json scenrio tests and I want to do a json comparison by using ignore paths instead of use "${json-unit.ignore}", Like :

assertThatJson(actualJson)//
.whenIgnore("path1", "path2", ...)//
isEqualTo(expectedJson);

Is it possible to do ?

Please remove logging from library

Hi

This is really a great library, but it should not depend on any logging framework.
I now get error messages on console while running unit tests:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation

Kind regards,
Michael

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.