通过JsonAssert进行比对

584 阅读2分钟

介绍

如今我们会给功能写单元测试,虽然很枯燥,但在规避一些修改造成的bug时,它们发挥着重要的作用。在编写单元测试时,一个绕不开的事情是:写assert。在复杂对象之间做assert,通常会对你关注的字段使用类似assertEquals一类的方法,这些方法在这种情况下会出现问题:你关注的字段没有变更,但其他字段变了。那么,有没有比较方便地对比全部字段的方法?而且能展示出具体哪个字段不一样?

JSONAssert是个不错的选择,它提供四种匹配风格:

风格允许额外字段顺序严格
STRICTnoyes
LENIENTyesno
NON_EXTENSIBLEnono
STRICT_ORDERyesyes

下面是演示。

演示

pom依赖

<dependency>
   <groupId>org.skyscreamer</groupId>
   <artifactId>jsonassert</artifactId>
   <version>1.5.0</version>
</dependency>

这里假设得到一个字符串的json,然后我们自己期望的数据是个object,此处引用了lombokjackson

json

String excepted = "{\n" +
        "  \"id\": 1,\n" +
        "  \"name\": \"Shivam\",\n" +
        "  \"address\": {\n" +
        "    \"line1\": \"--line 1\",\n" +
        "    \"line2\": \"--line 2\",\n" +
        "    \"city\": \"Bengaluru\",\n" +
        "    \"state\": \"Karnataka\",\n" +
        "    \"country\": \"India\",\n" +
        "    \"pincode\": 560037,\n" +
        "    \"hideMe\":111\n"+
        "  }\n" +
        "}";

object

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
static class Employee {

    private int id;
    private String name;
    private Address address;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
static class Address {
    private String line1;
    private String line2;
    private String city;
    private String state;
    private String country;
    private int pincode;
}

......

Employee employee = Employee.builder()
        .id(1)
        .name("Shivam")
        .address(
                Address.builder()
                        .line1("line 1a")
                        .city("Bengaluru")
                        .country("India")
                        .state("Karnataka")
                        .pincode(560037)
                        .build())
        .build();

简单比对

测试用例

@Test
public void justAssert() throws JsonProcessingException, JSONException {
    ObjectMapper objectMapper = new ObjectMapper();
    JSONObject jsonObject = new JSONObject(objectMapper.writeValueAsString(employee));
    JSONAssert.assertEquals(excepted,jsonObject, JSONCompareMode.LENIENT);
}

输出

java.lang.AssertionError: address
Expected: hideMe
     but none found
 ; address.line1
Expected: --line 1
     got: line 1a
 ; address.line2
Expected: --line 2
     got: null

自定义处理比对结果

这是我非常喜欢的一个功能,你可以按你的想法自行处理比对结果,我这边只是简单地转成了中文

@Test
public void walkResult()throws JsonProcessingException, JSONException{
    ObjectMapper objectMapper = new ObjectMapper();
    JSONCompareResult result = JSONCompare.compareJSON(excepted,objectMapper.writeValueAsString(employee),JSONCompareMode.LENIENT);
    System.out.println("比对失败字段:");
    for(FieldComparisonFailure f1 :result.getFieldFailures()){
        System.out.println("字段:"+f1.getField()+"\t期望:"+f1.getExpected()+"\t实际:"+f1.getActual());
    }
    System.out.println("\n比对缺失字段");
    for(FieldComparisonFailure f2 :result.getFieldMissing()){
        System.out.println("字段:"+f2.getField()+"\t期望:"+f2.getExpected()+"\t实际:"+f2.getActual());
    }
    System.out.println("\n比对多余字段");
    for(FieldComparisonFailure f3 :result.getFieldUnexpected()){
        System.out.println("字段:"+f3.getField()+"\t期望:"+f3.getExpected()+"\t实际:"+f3.getActual());
    }
}

输出

比对失败字段:
字段:address.line1	期望:--line 1	实际:line 1a
字段:address.line2	期望:--line 2	实际:null

比对缺失字段
字段:address	期望:hideMe	实际:null

比对多余字段

参考文献

Comparing Complex Objects with JSONAssert

官方文档