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