我们有时不需要比较 JSON 文档里的所有节点,比较时需忽略一些不匹配的结点。一个现实的例子就是一个时间戳字段,它是变化的,在比较时我们必须忽略这些变化的字段。
前提条件添加 JSonassert 依赖
org.skyscreamer jsonassert 1.5.0 test
请先阅读下面文章,了解 JSonassert Java library 基本概念 ,不同的比较模式和断言 JSON Objects 和 Array。
Introduction To JsonAssert Library
Compare JSON Objects Using JSonassert Library
Compare JSON Arrays Using JSonassert Library
比较时怎么忽略 JSON 中的字段没有直接的方法去忽略某些字段和属性,我们需要用到 CustomComparator。
JSONComparator com = new CustomComparator(JSONCompareMode.LENIENT,
new Customization("salary", (o1, o2) -> true));
CustomComparator 是一个类,它间接实现 JSONComparator。 Customization 是另外一个类,CustomComparator 的构造函数接收 JSonCompareMode 和一个 Customization 类型的数组。Customization 类的构造函数接收一个包含 euqal() 方法的 ValueMatcher 接口的引用,
// Constructor of CustomComparator
public CustomComparator(JSONCompareMode mode, Customization... customizations) {
super(mode);
this.customizations = Arrays.asList(customizations);
}
为了忽略某些字段,跟 JSONassert是没有啥关系的,而是显示地让这些忽略的字段断言 PASS。如果我们从第一个 JSON 文档中获取的值为 v1, 第二个 JSON 文档中的值为 v2,v1 可以等于 或 不等于 v2. 我们就像弄了一个代理,显示地将 v1 和 v2 是相等的,或者说是匹配成功的。
上面的代码中,“salary” 是一个 JSON path,“o1” 和 “o2” 分别是从 JSON 文档中获取的值。无条件使得这两个值是相等的,返回 true。
也可以传多个 Customization 引用,因为 CustomComparator 接收的是 Customization 类型的数组。
JSONComparator com = new CustomComparator(JSONCompareMode.LENIENT,
new Customization("salary", (o1, o2) -> true),
new Customization("age", (o1, o2) -> true));
JSonAssert 类的重载方法 assertEquals() 接收 JSonComparator 引用参数。
忽略简单 JSON object 的字段JSON String 1
{
"id": 1,
"first_name": "Amod",
"last_name": "Mahajan",
"married": false,
"salary": 123.45
}
JSON String 2
{
"id": 1,
"first_name": "Amod",
"last_name": "Mahajan",
"married": false,
"salary": 125.45
}
比较时,忽略 “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 IgnoringFieldsFromSimpleJsonObjects {
public static void main(String[] args) throws JSONException {
String s1 = "{rn" +
" "id": 1,rn" +
" "first_name": "Amod",rn" +
" "last_name": "Mahajan",rn" +
" "married": false,rn" +
" "salary": 123.45rn" +
"}";
String s2 = "{rn" +
" "id": 1,rn" +
" "first_name": "Amod",rn" +
" "last_name": "Mahajan",rn" +
" "married": false,rn" +
" "salary": 125.45rn" +
"}";
JSONComparator com = new CustomComparator(JSONCompareMode.LENIENT,
new Customization("salary", (o1, o2) -> true));
JSONAssert.assertEquals(s1, s2, com);
}
}
忽略嵌套的 JSON Object 的字段
JSON Object 1
{
"id": 1,
"first_name": "Amod",
"last_name": "Mahajan",
"married": false,
"salary": 123.45,
"address":{
"permanent" : "KA",
"city": "Bengaluru"
}
}
JSON Object 2
{
"id": 1,
"first_name": "Amod",
"last_name": "Mahajan",
"married": false,
"salary": 123.45,
"address":{
"permanent" : "KA",
"city": "Katihar"
}
}
比较时忽略 “address” 字段里面的 “city” 结点。我们需要提供忽略字段正确的 JSON path, “address.city“。
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 IgnoringFieldsFromNestedJsonObjects {
public static void main(String[] args) throws JSONException {
String s1 = "{rn" +
" "id": 1,rn" +
" "first_name": "Amod",rn" +
" "last_name": "Mahajan",rn" +
" "married": false,rn" +
" "salary": 123.45,rn" +
" "address":{rn" +
" "permanent" : "KA",rn" +
" "city": "Bengaluru"rn" +
" }rn" +
"}";
String s2 = "{rn" +
" "id": 1,rn" +
" "first_name": "Amod",rn" +
" "last_name": "Mahajan",rn" +
" "married": false,rn" +
" "salary": 123.45,rn" +
" "address":{rn" +
" "permanent" : "KA",rn" +
" "city": "Katihar"rn" +
" }rn" +
"}";
JSONComparator com = new CustomComparator(JSONCompareMode.LENIENT,
new Customization("address.city", (o1, o2) -> true));
JSONAssert.assertEquals(s1, s2, com);
}
}
忽略简单 JSON Array 中的字段
JSON Array 1
[{
"id": 1,
"first_name": "Amod",
"last_name": "Mahajan",
"married": false,
"salary": 123.45
},
{
"id": 2,
"first_name": "Animesh",
"last_name": "Prashant",
"married": true,
"salary": 223.45
}]
JSON Array 2
[{
"id": 10,
"first_name": "Amod",
"last_name": "Mahajan",
"married": false,
"salary": 123.45
},
{
"id": 2,
"first_name": "Animesh",
"last_name": "Prashant",
"married": true,
"salary": 223.45
}]
建设我们不想比较数组中第一个 JSON Object 的 ”id“ 字段。我们需要忽略的 JSON path 就是 “[0].id”,但是如果我们选择的是 LENIENT mode,字段是不会忽略的。针对特定索引的元素,我们应该用 STRICT mode。
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 IgnoringFieldsFromSimpleJsonArray {
public static void main(String[] args) throws JSONException {
String s1 = "[{rn" +
" "id": 1,rn" +
" "first_name": "Amod",rn" +
" "last_name": "Mahajan",rn" +
" "married": false,rn" +
" "salary": 123.45rn" +
"},rn" +
"{rn" +
" "id": 2,rn" +
" "first_name": "Animesh",rn" +
" "last_name": "Prashant",rn" +
" "married": true,rn" +
" "salary": 223.45rn" +
"}]";
String s2 = "[{rn" +
" "id": 10,rn" +
" "first_name": "Amod",rn" +
" "last_name": "Mahajan",rn" +
" "married": false,rn" +
" "salary": 123.45rn" +
"},rn" +
"{rn" +
" "id": 2,rn" +
" "first_name": "Animesh",rn" +
" "last_name": "Prashant",rn" +
" "married": true,rn" +
" "salary": 223.45rn" +
"}]";
JSONComparator com = new CustomComparator(JSONCompareMode.STRICT,
new Customization("[0].id", (o1, o2) -> true));
JSONAssert.assertEquals(s1, s2, com);
}
}
如果我们想忽略所有索引元素,我们可以传递 “[*].id“ JSON path,就可以用 STRICT 或 LENIENT mode 了。
忽略嵌套的 JSON Array 中的字段JSON Array 1
[
{
"id": 1,
"first_name": "Amod",
"last_name": "Mahajan",
"married": false,
"salary": 123.45,
"mob": [
{
"type": "personal",
"number": "1234566"
},
{
"type": "business",
"number": "987654321"
}
]
},
{
"id": 2,
"first_name": "Animesh",
"last_name": "Prashant",
"married": true,
"salary": 223.45,
"mob": [
{
"type": "personal",
"number": "1234566"
},
{
"type": "business",
"number": "987654321"
}
]
}
]
JSON Array 2
[
{
"id": 1,
"first_name": "Amod",
"last_name": "Mahajan",
"married": false,
"salary": 123.45,
"mob": [
{
"type": "personal",
"number": "1234566"
},
{
"type": "business",
"number": "34545646"
}
]
},
{
"id": 2,
"first_name": "Animesh",
"last_name": "Prashant",
"married": true,
"salary": 223.45,
"mob": [
{
"type": "personal",
"number": "1234566"
},
{
"type": "business",
"number": "987654321"
}
]
}
]
假设想忽略第一个索引元素中第二个 mobile 中的 ”number“ 字段,那么 json path 就是 “[0].mob[1].number“
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 IgnoringFieldsFromNestedJsonArray {
public static void main(String[] args) throws JSONException {
String s1 = "[rn" +
" {rn" +
" "id": 1,rn" +
" "first_name": "Amod",rn" +
" "last_name": "Mahajan",rn" +
" "married": false,rn" +
" "salary": 123.45,rn" +
" "mob": [rn" +
" {rn" +
" "type": "personal",rn" +
" "number": "1234566"rn" +
" },rn" +
" {rn" +
" "type": "business",rn" +
" "number": "987654321"rn" +
" }rn" +
" ]rn" +
" },rn" +
" {rn" +
" "id": 2,rn" +
" "first_name": "Animesh",rn" +
" "last_name": "Prashant",rn" +
" "married": true,rn" +
" "salary": 223.45,rn" +
" "mob": [rn" +
" {rn" +
" "type": "personal",rn" +
" "number": "1234566"rn" +
" },rn" +
" {rn" +
" "type": "business",rn" +
" "number": "987654321"rn" +
" }rn" +
" ]rn" +
" }rn" +
"]";
String s2 = "[rn" +
" {rn" +
" "id": 1,rn" +
" "first_name": "Amod",rn" +
" "last_name": "Mahajan",rn" +
" "married": false,rn" +
" "salary": 123.45,rn" +
" "mob": [rn" +
" {rn" +
" "type": "personal",rn" +
" "number": "1234566"rn" +
" },rn" +
" {rn" +
" "type": "business",rn" +
" "number": "34545646"rn" +
" }rn" +
" ]rn" +
" },rn" +
" {rn" +
" "id": 2,rn" +
" "first_name": "Animesh",rn" +
" "last_name": "Prashant",rn" +
" "married": true,rn" +
" "salary": 223.45,rn" +
" "mob": [rn" +
" {rn" +
" "type": "personal",rn" +
" "number": "1234566"rn" +
" },rn" +
" {rn" +
" "type": "business",rn" +
" "number": "987654321"rn" +
" }rn" +
" ]rn" +
" }rn" +
"]";
System.out.println(s1);
System.out.println(s2);
JSONComparator com = new CustomComparator(JSONCompareMode.STRICT,
new Customization("[0].mob[1].number",(o1, o2) -> true));
JSONAssert.assertEquals(s1, s2, com);
}
}
注意,比较时如果忽略的 JSON path 在 JSON 文档中找不到, 测试将会失败。



