There is a library called JSONassert that compares JSON in Java, but this time, when comparing JSON with that library, a regular expression is used for value matching. I would like to briefly introduce how to apply it.
Use CustomComparator
to specify the item for which you want to treat the expected value as a regular expression as shown below.
JSON to be verified
{
"array": [
1,
2
],
"id": 100,
"type": "foo",
"object": {
"name": "Kazuki",
"token": "ac648657-797e-49f7-9563-150c9b5c2284"
}
}
JSON that expresses the expected value
{
"array": [
1,
2
],
"id": 100,
"type": "foo",
"object": {
"name": "Kazuki",
"token": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
}
}
The following is an example of specification when comparing ʻobject.token` using a regular expression.
Comparison method call example
JSONAssert.assertEquals(expectedJson.toString(2), actualJson.toString(2),
new CustomComparator(JSONCompareMode.STRICT,
new Customization("object.token", new RegularExpressionValueMatcher<>()) //Match using the pattern specified for the expected value
)
);
You can also specify a pattern during verification as shown below.
Example of specifying a pattern during verification
JSONAssert.assertEquals(expectedJson.toString(2), actualJson.toString(2),
new CustomComparator(JSONCompareMode.STRICT,
new Customization("object.token", new RegularExpressionValueMatcher<>("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")) //Matching using the pattern specified here without using the value described in the expected value JSON
)
);
In the standard feature, regular expression application is item-by-item (as far as I know) (maybe wildcard-like specification of paths is supported !?). So ... I'd like to create my own JSONComparator
that can match all items using regular expressions without using CustomComparator
.
Example of creating JSONComparator
public class RegularExpressionComparator extends DefaultComparator {
private static final RegularExpressionValueMatcher<Object> REGEX_VALUE_MATCHER = new RegularExpressionValueMatcher<>();
private final ValueMatcher<Object> matcher;
public RegularExpressionComparator(JSONCompareMode mode) {
super(mode);
//Adopt a method of comparing once with an exact match, and in the case of NG, falling back to matching with a regular expression
//Most items can be exact matches, which can reduce processing costs compared to unconditionally matching with regular expressions (should).
this.matcher = (actual, expected) -> Objects.equals(actual, expected) ||
expected instanceof String && REGEX_VALUE_MATCHER.equal(actual, expected);
}
@Override
public void compareValues(String prefix, Object expectedValue, Object actualValue, JSONCompareResult result) throws JSONException {
if (actualValue instanceof JSONArray || actualValue instanceof JSONObject) {
//container(Object + array)If it is an object, transfer it to the default implementation
super.compareValues(prefix, expectedValue, actualValue, result);
} else {
//For values (strings, numbers, booleans), call the regular expression support ValueMatcher to compare
try {
if (!matcher.equal(actualValue, expectedValue)) {
//Error handling when it is judged that there is a mismatch when it is not matched by regular expression
result.fail(prefix, expectedValue, actualValue);
}
} catch (ValueMatcherException e) {
//Error handling when a regular expression matching determines a mismatch
result.fail(prefix, e);
}
}
}
}
For reference, I will also paste the test case created at the time of verification.
package com.example.assertdemo;
import java.util.Objects;
import java.util.UUID;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Test;
import org.skyscreamer.jsonassert.JSONAssert;
import org.skyscreamer.jsonassert.JSONCompareMode;
import org.skyscreamer.jsonassert.JSONCompareResult;
import org.skyscreamer.jsonassert.RegularExpressionValueMatcher;
import org.skyscreamer.jsonassert.ValueMatcher;
import org.skyscreamer.jsonassert.ValueMatcherException;
import org.skyscreamer.jsonassert.comparator.DefaultComparator;
public class JSONAssertRegexTests {
@Test
public void regexAssert() throws JSONException {
JSONObject expectedJson = new JSONObject();
{
JSONArray array = new JSONArray();
array.put(1);
array.put(2);
JSONObject object = new JSONObject();
object.put("name", "Kazuki");
object.put("token", "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}");
expectedJson.put("id", 100);
expectedJson.put("type", "foo");
expectedJson.put("array", array);
expectedJson.put("object", object);
System.out.println("-----expectedJson------");
System.out.println(expectedJson.toString(2));
}
JSONObject actualJson = new JSONObject();
{
JSONArray array = new JSONArray();
array.put(1);
array.put(2);
actualJson.put("id", 100);
actualJson.put("array", array);
JSONObject object = new JSONObject();
object.put("name", "Kazuki");
object.put("token", UUID.randomUUID().toString());
actualJson.put("id", 100);
actualJson.put("type", "foo");
actualJson.put("array", array);
actualJson.put("object", object);
System.out.println("-----actualJson------");
System.out.println(actualJson.toString(2));
}
JSONAssert.assertEquals(expectedJson.toString(2),
actualJson.toString(2),
new RegularExpressionComparator(JSONCompareMode.STRICT));
}
public static class RegularExpressionComparator extends DefaultComparator {
private static final RegularExpressionValueMatcher<Object> REGEX_VALUE_MATCHER = new RegularExpressionValueMatcher<>();
private final ValueMatcher<Object> matcher;
public RegularExpressionComparator(JSONCompareMode mode) {
super(mode);
this.matcher = (actual, expected) -> Objects.equals(actual, expected) ||
expected instanceof String && REGEX_VALUE_MATCHER.equal(actual, expected);
}
@Override
public void compareValues(String prefix, Object expectedValue, Object actualValue, JSONCompareResult result) throws JSONException {
if (actualValue instanceof JSONArray || actualValue instanceof JSONObject) {
super.compareValues(prefix, expectedValue, actualValue, result);
} else {
try {
if (!matcher.equal(actualValue, expectedValue)) {
result.fail(prefix, expectedValue, actualValue);
}
} catch (ValueMatcherException e) {
result.fail(prefix, e);
}
}
}
}
}
There is no problem with the standard function alone, but I wanted an implementation that "matches all items with regular expressions" ...- JSON expected when verifying the response BODY of the Web API Is prepared as a file, and in order to adopt a mechanism that compares the actual response data with the JSON read from the expected value file, use CustomComparator
in each test case to set the target item. I thought it would be (a little) difficult to specify, and I wanted to be able to apply it automatically by specifying a regular expression in the expected value file.
Recommended Posts