You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中如何语义化比较JSON数组?单元测试遇问题求助

解决JSON数组对象键顺序不同但语义相同的单元测试比较问题

我明白你遇到的困扰了——明明两个JSON数组的元素语义完全一致,只是每个对象的键顺序颠倒,用在线工具判定是相同的,但用org.skyscreamer.jsonassert的默认比较模式却始终判定为不同。这是因为默认的LENIENT模式仅忽略数组元素的顺序,并不会忽略对象内部键的顺序,而STRICT模式会同时检查这两者,所以才会出现不符合预期的结果。

下面给你几个实用的解决方案:


方案1:自定义JSONComparator忽略对象键顺序

你可以扩展jsonassert库的比较逻辑,创建一个忽略对象键顺序的自定义比较器:

import org.skyscreamer.jsonassert.*;
import org.json.JSONArray;
import org.json.JSONObject;

public class IgnoreKeyOrderComparator extends DefaultComparator {
    public IgnoreKeyOrderComparator(JSONCompareMode mode) {
        super(mode);
    }

    @Override
    public void compareValues(String prefix, Object expected, Object actual, JSONCompareResult result) throws JSONException {
        if (expected instanceof JSONObject && actual instanceof JSONObject) {
            JSONObject expectedObj = (JSONObject) expected;
            JSONObject actualObj = (JSONObject) actual;
            
            // 先校验键的集合是否完全匹配
            if (!expectedObj.keySet().equals(actualObj.keySet())) {
                result.fail(prefix, expectedObj, actualObj);
                return;
            }
            
            // 逐个比较键对应的值,忽略键的顺序
            for (String key : expectedObj.keySet()) {
                String newPrefix = prefix + "." + key;
                compareValues(newPrefix, expectedObj.get(key), actualObj.get(key), result);
            }
        } else {
            // 非对象类型按默认逻辑比较
            super.compareValues(prefix, expected, actual, result);
        }
    }
}

测试时使用这个自定义比较器:

// 假设Array1和Array2是合法的JSON字符串或JSONArray对象
JSONCompareResult result = JSONCompare.compareJSON(Array1, Array2, new IgnoreKeyOrderComparator(JSONCompareMode.LENIENT));
assertTrue(result.passed());

// 或者用JSONAssert的重载方法
JSONAssert.assertEquals(Array1, Array2, new IgnoreKeyOrderComparator(JSONCompareMode.LENIENT));

方案2:解析为List后直接比较

另一种更简洁的方式是把JSON数组转换成Java的List<Map<String, Object>>,因为Map本身不关心键的顺序,只要键值对完全匹配即可。这里以Jackson库为例:

import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;
import java.util.Map;

// 初始化ObjectMapper
ObjectMapper mapper = new ObjectMapper();

// 解析JSON数组为List<Map>
List<Map<String, Object>> list1 = mapper.readValue(Array1, List.class);
List<Map<String, Object>> list2 = mapper.readValue(Array2, List.class);

// 直接比较两个列表(如果数组元素顺序无关,可先排序后再比较)
assertEquals(list1, list2);

如果用Gson库,代码逻辑类似:

import com.google.gson.Gson;
import java.util.List;
import java.util.Map;

Gson gson = new Gson();
List<Map<String, Object>> list1 = gson.fromJson(Array1, List.class);
List<Map<String, Object>> list2 = gson.fromJson(Array2, List.class);

assertEquals(list1, list2);

方案3:转换成自定义实体类列表比较(推荐)

如果你的JSON结构固定,最稳妥的方式是定义对应的Java实体类,将JSON转换成实体类列表后再比较。这种方式类型安全,测试逻辑也更清晰:

首先定义实体类:

import java.util.Objects;

public class RoleJob {
    private String job_name;
    private String role_name;

    // 生成getter、setter方法
    public String getJob_name() {
        return job_name;
    }

    public void setJob_name(String job_name) {
        this.job_name = job_name;
    }

    public String getRole_name() {
        return role_name;
    }

    public void setRole_name(String role_name) {
        this.role_name = role_name;
    }

    // 重写equals和hashCode方法
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        RoleJob roleJob = (RoleJob) o;
        return Objects.equals(job_name, roleJob.job_name) && Objects.equals(role_name, roleJob.role_name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(job_name, role_name);
    }
}

然后解析并比较:

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;

ObjectMapper mapper = new ObjectMapper();
List<RoleJob> roles1 = mapper.readValue(Array1, new TypeReference<List<RoleJob>>() {});
List<RoleJob> roles2 = mapper.readValue(Array2, new TypeReference<List<RoleJob>>() {});

assertEquals(roles1, roles2);

最后提醒一句:你提供的JSON Array2看起来缺少外层的[],这会导致解析失败,记得修正为合法的JSON数组格式哦。

内容的提问来源于stack exchange,提问作者supratim dutta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:16:15