REST Assured 系列汇总 之 REST Assured 74 - Problem With JSONassert While Ignoring Fields From JSON Documents
介绍
JSONassert 库用来比较 JSON 文档,比较文档时,我们会自定义一些忽略的字段,当忽略的字段不存在时,将发生什么?
简单的 JSON object 中没有被忽略的字段
我们知道 how to ignore fields from a comparison in JSON Objects ,但是有可能这些忽略的字段在 JSON Objects中不存在。特别是对动态的 JSON Objects,我不知道字段总是存在的。我们可以通过一个例子来了解一下。
请注意:当一个字段不存在于第二个 JSON object会出现问题,而字段不存在于第一个 JSON Object时不会出错。
JSON Object 1
{
"id": 1,
"first_name": "Amod",
"last_name": "Mahajan",
"married": false,
"salary": 123.45
}
JSON Object 2
{
"id": 1,
"first_name": "Amod",
"last_name": "Mahajan",
"married": false
}
上面两个 JSON Objects, “Salary” 不存在于第二个 JSON Object 中。要忽略 “Salary” 字段,假设这个字段可能存在,可能不存在。现实场景中,董事会的 “Salary” 是不可见的。
import org.json.JSONException;
import org.skyscreamer.jsonassert.Customization;
import org.skyscreamer.jsonassert.JSONAssert;
import org.skyscreamer.jsonassert.JSONCompareMode;
import org.skyscreamer.jsonassert.comparator.CustomComparator;
import org.skyscreamer.jsonassert.comparator.JSONComparator;
public class IgnoringFieldsFromSimpleJsonObjectsNonExistence {
public static void main(String[] args) throws JSONException {
String s1 = "{\r\n" +
" \"id\": 1,\r\n" +
" \"first_name\": \"Amod\",\r\n" +
" \"last_name\": \"Mahajan\",\r\n" +
" \"married\": false,\r\n" +
" \"salary\": 123.45\r\n" +
"}";
String s2 = "{\r\n" +
" \"id\": 1,\r\n" +
" \"first_name\": \"Amod\",\r\n" +
" \"last_name\": \"Mahajan\",\r\n" +
" \"married\": false\r\n" +
"}";
JSONComparator com = new CustomComparator(JSONCompareMode.LENIENT,
new Customization("salary", (o1, o2) -> true));
JSONAssert.assertEquals(s1, s2, com);
}
}
结果:
可以看出,当被忽略的字段不存在于第二个 JSON object 中会有 AssertionError。这不是我们想要的,如果字段被忽略,就应该忽略检查是否存在这个问题。
没有直接的方法解决这个问题,我们需要重载方法。
解决方法
如果你调试代码,就会发现有一个 “AbstractComparator” 抽象类中有一个 “checkJsonObjectKeysExpectedInActual()” 方法,这个方法被内部调用了,默认的实现是这样的:
protected void checkJsonObjectKeysExpectedInActual(String prefix, JSONObject expected, JSONObject actual, JSONCompareResult result) throws JSONException {
Set<String> expectedKeys = getKeys(expected);
for (String key : expectedKeys) {
Object expectedValue = expected.get(key);
if (actual.has(key)) {
Object actualValue = actual.get(key);
compareValues(qualify(prefix, key), expectedValue, actualValue, result);
} else {
result.missing(prefix, key);
}
}
}
默认,会检查字段是否存在于 JSON Object,我们可以重载这人方法,直接移除忽略字段的检查。
import java.util.Set;
import org.json.JSONException;
import org.json.JSONObject;
import org.skyscreamer.jsonassert.Customization;
import org.skyscreamer.jsonassert.JSONCompareMode;
import org.skyscreamer.jsonassert.JSONCompareResult;
import org.skyscreamer.jsonassert.comparator.CustomComparator;
public class MyComparator extends CustomComparator{
private final Set<String> attributesToIgnore;
public MyComparator(JSONCompareMode mode, Set<String> attributesToIgnore, Customization... customizations) {
super(mode, customizations);
this.attributesToIgnore = attributesToIgnore;
}
@Override
protected void checkJsonObjectKeysExpectedInActual(String prefix, JSONObject expected, JSONObject actual, JSONCompareResult result) throws JSONException {
//Remove ignored keys from json object
attributesToIgnore.forEach(attribute -> expected.remove(attribute));
super.checkJsonObjectKeysExpectedInActual(prefix, expected, actual, result);
}
}
import java.util.Arrays;
import java.util.HashSet;
import org.json.JSONException;
import org.skyscreamer.jsonassert.Customization;
import org.skyscreamer.jsonassert.JSONAssert;
import org.skyscreamer.jsonassert.JSONCompareMode;
import org.skyscreamer.jsonassert.comparator.JSONComparator;
public class IgnoreFieldsUsingMyComparator {
public static void main(String[] args) throws JSONException {
String s1 = "{\r\n" +
" \"id\": 1,\r\n" +
" \"first_name\": \"Amod\",\r\n" +
" \"last_name\": \"Mahajan\",\r\n" +
" \"married\": false,\r\n" +
" \"salary\": 123.45\r\n" +
"}";
String s2 = "{\r\n" +
" \"id\": 1,\r\n" +
" \"first_name\": \"Amod\",\r\n" +
" \"last_name\": \"Mahajan\",\r\n" +
" \"married\": false\r\n" +
"}";
JSONComparator com = new MyComparator(JSONCompareMode.LENIENT,
// Pass attributes to ignore
new HashSet<String>(Arrays.asList("salary")),
new Customization("firstName", (o1, o2) -> true),
new Customization("age", (o1, o2) -> true));
JSONAssert.assertEquals(s1, s2,com);
}
}
这次比较就会 PASS了,但是这种方式不适合嵌套的 JSON Object 或 Arrays。需要重载更多方法去解决 JSON Object 或 Arrays 的问题。