As mentioned in This Topic,I would like to include JsonUnit with contribution from : Anas Aitbaha in order to ignore value when request matching using equalToJson as it is the case in equalToXml body pattern .
example from json-unit :
assertThatJson("{\"test\":1}").isEqualTo("{\"test\":\"${json-unit.ignore}\"}");
Thanks for raising this. I think using JsonUnit might be a great idea.
Here are my initial thoughts (which I'm sure I'll end up adding to once I've had more time to think about it):
EqualToJsonPattern
. It should therefore maintain backwards compatibility, including the existing ignoreExtraElements
and ignoreArrayOrder
parameters.EqualToXmlPattern
achieves this by attaching a ComparisonListener
to XMLUnit and incrementing each time a node doesn't match.Here is a quick fix that I ve chosen to get some results. The quality of the code is not good , but it still works well.
```@Override
public MatchResult match(String value) {
try {
final JsonNode actual = Json.read(value, JsonNode.class);
final String actualJson = value;
return new MatchResult() {
@Override
public boolean isExactMatch() {
// Try to do it the fast way first, then fall back to doing the full diff
if (!shouldIgnoreArrayOrder() && !shouldIgnoreExtraElements()) {
try {
assertThatJson(expected).isEqualTo(actual);
return true;
} catch (Error e) {
return getDistanceWhenIsNotExactMatch()==0;
}
} else if (shouldIgnoreArrayOrder() && shouldIgnoreExtraElements()) {
try {
assertThatJson(expectedJson).when(Option.IGNORING_ARRAY_ORDER).when(IGNORING_EXTRA_FIELDS).isEqualTo(actualJson);
return true;
} catch (Error e) {
try {
assertThatJson(actualJson).when(Option.IGNORING_ARRAY_ORDER).when(IGNORING_EXTRA_FIELDS).isEqualTo(expectedJson);
return true;
} catch (Error aE) {
return getDistanceWhenIsNotExactMatch()==0;
}
}
} else if (!shouldIgnoreArrayOrder() && shouldIgnoreExtraElements()) {
try {
assertThatJson(actualJson).when(IGNORING_EXTRA_FIELDS).isEqualTo(expectedJson);
return true;
} catch (Error e) {
try {
assertThatJson(expectedJson).when(IGNORING_EXTRA_FIELDS).isEqualTo(actualJson);
return true;
} catch (Error aE) {
return getDistanceWhenIsNotExactMatch()==0;
}
}
} else if (shouldIgnoreArrayOrder() && !shouldIgnoreExtraElements()) {
try {
assertThatJson(expectedJson).when(Option.IGNORING_ARRAY_ORDER).isEqualTo(actual);
return true;
} catch (Error e) {
return getDistanceWhenIsNotExactMatch()==0;
}
}
return false;
}
@Override
public double getDistance() {
if (!isExactMatch()) {
return getDistanceWhenIsNotExactMatch();
} else {
return 0.0;
}
}
public double getDistanceWhenIsNotExactMatch() {
EnumSet<DiffFlags> flags = EnumSet.of(OMIT_COPY_OPERATION);
ArrayNode diff = (ArrayNode) JsonDiff.asJson(expected, actual, flags);
double maxNodes = maxDeepSize(expected, actual);
return diffSize(diff) / maxNodes;
}
};
} catch (Exception e) {
return MatchResult.noMatch();
}
}
```
I'm not keen on the idea of using exceptions for control flow as there's quite a big performance penalty doing it that way.
Presumably it's possible to call the API a layer down so that you can get a boolean or diff result of some kind rather than make an assertion?
Possibly a more elegant solution for verification could be:
verify(requestMadeFor(value -> {
assertThatJson(value.getBodyAsString()).withMatcher("matcherName", new SomeCustomMatcher())
.isEqualTo(expectedBody);
return MatchResult.exactMatch();
}));
Now, you've left JSON assertion completely to json-unit. Note that the custom matcher is not required; json-unit.ignore will work out of the box, but custom matches are useful.
This would be a great addition for much more expressive pattern matching of JSON body content. Unfortunately it doesn鈥檛 look like this can be changed externally via an extension and must replace the current EqualToJsonPattern. However, I think it will definitely improve both common and advanced use cases.
Most helpful comment
Possibly a more elegant solution for verification could be:
Now, you've left JSON assertion completely to json-unit. Note that the custom matcher is not required; json-unit.ignore will work out of the box, but custom matches are useful.