Praveen Kumar Mekala
Praveen Kumar Mekala

Reputation: 638

Error in JSON array comparison customization(sky-screamer)

I have below two JSONs to compare,

expected json:

 [
  {
    "id": 1,
    "code": 1,
    "createdOn": null,
    "lastModifiedOn": null

  },
  {
    "id": 2,
    "code": 1,
    "createdOn": null,
    "lastModifiedOn": null
  }
]

actual json

[
  {
    "id": 1,
    "code": 1,
    "createdOn": "2019-12-31",
    "lastModifiedOn": "2019-12-31",
  },
  {
    "id": 2,
    "code": 1,
    "createdOn": "2019-12-31",
    "lastModifiedOn": "2019-12-31",
  }
]

Trying to compare by ignoring couple of nodes using below code

JSONAssert.assertEquals(actualjson, expectedjson,
new CustomComparator(JSONCompareMode.STRICT, 
    new Customization("createdOn", (o1, o2) -> {
        return true;
    }), 
    new Customization("lastModifiedOn", (o1, o2) -> {
        return true;
    })
)));

but it is failing with below assertion exception,

java.lang.AssertionError: [0].createdOn
Expected: null
     got: 2019-12-31
 ; [0].lastModifiedOn
Expected: null
     got: 2019-12-31
 ; [1].createdOn
Expected: null
     got: 2019-12-31
 ; [1].lastModifiedOn
Expected: null
     got: 2019-12-31

how can I compare array of json values with customization object by skipping createdon and lastmodifiedon nodes?

<groupId>org.assertj</groupId>
<version>2.2.1</version>

Upvotes: 1

Views: 2304

Answers (6)

Devin Li
Devin Li

Reputation: 1

Since the field is nested in an object, just add a [*]. before it

// [*] - any index
// .key - key of object

new Customization("[*].createdOn", (o1, o2) -> true)
// for any index in the root array, use this above comparison for the .createdOn field

Btw: function call should be like: JSONAssert.assertEquals(expected, actual, ...other stuff)

Upvotes: 0

ARC
ARC

Reputation: 21

Yes below code snippet

JSONAssert.assertEquals(actualjson, expectedjson,
new CustomComparator(JSONCompareMode.STRICT, 
    new Customization("**.createdOn", (o1, o2) -> true), 
    new Customization("**.lastModifiedOn", (o1, o2) -> true)
)));

Eventually Customization.getCustomization method invoke appliesToPath method , which invoke this.path.matcher(path).matches();

matcher method is from java.util.regex , so if your pattern "**.createdOn" matches with path "[0].createdOn" , "[1].createdOn" then your Customisation will be added CustomComparator which inturn call your method "(o1, o2) -> true"

Upvotes: 2

jk.
jk.

Reputation: 7676

I recently created a custom comparator that lets you use regular expressions in the 'expected' JSON:

public class ExtendedJsonComparator extends DefaultComparator {
    public ExtendedJsonComparator(JSONCompareMode mode) {
        super(mode);
    }

    @Override
    public void compareValues(String prefix, Object expectedValue, Object actualValue, JSONCompareResult result) throws JSONException {
        String expected = expectedValue.toString().trim();
        String actual = actualValue.toString();
        if(expected.startsWith("${") && expected.endsWith("}")) {
            String regex = expected.substring(2, expected.length() - 1);
            if(!actual.matches(regex)) {
                result.fail(prefix, expected, actual);
            }
        } else {
            super.compareValues(prefix, expectedValue, actualValue, result);
        }
    }
}

For 'expected, you can then do the following, or create a regex to match your date format, if that's something you're testing:

[
  {
    "id": 1,
    "code": 1,
    "createdOn": "${.*}",
    "lastModifiedOn": "${.*}"

  },
  {
    "id": 2,
    "code": 1,
    "createdOn": "${.*}",
    "lastModifiedOn": "${.*}"
  }
]

Upvotes: 0

Praveen Kumar Mekala
Praveen Kumar Mekala

Reputation: 638

Since SkyScreamer has open issue noted in github I found temporary solution and thought would be helpful for others,

https://github.com/skyscreamer/JSONassert/issues/109

solution:

ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new JavaTimeModule());
    List<DomainObject> actualDomainObj = mapper.readValue(actualJson, new TypeReference<List<DomainObject>>() {
    });
    List<DomainObject> expectedDomainObj = mapper.readValue(expectedJson, new TypeReference<List<DomainObject>>() {
    });
    assertDomainObjResults(actualDomainObj.get(0), expectedDomainObj.get(0));


private void assertDomainObjResults(DomainObject actual, DomainObject expected) {
    softAssertions.assertThat(actual.getId()).isEqualTo(expected.getId());
    softAssertions.assertThat(actual.getLastModifiedOn()).isEqualTo(LocalDate.now());
    softAssertions.assertThat(actual.getCreatedOn()).isEqualTo(LocalDate.now());
}

accept the answer if someone finds it useful.

Upvotes: 0

Joel Costigliola
Joel Costigliola

Reputation: 7066

Give a try to JsonUnit it allows you to ignore values, elements or path which should help.

Upvotes: 0

Swanand
Swanand

Reputation: 103

Approach 1: Parse the JSON and recreate the two object JSONs without the date properties.

Approach 2: Parse the JSON and put an assertion on each property to be compared.

Upvotes: 0

Related Questions