
JSONAssert 默认按字符串精确匹配数值字段,导致 "123" 与 "123.00" 比较失败;本文详解通过类型标准化、逻辑比较模式或自定义 Comparator 实现语义等价校验,无需忽略字段。
jsonassert 默认按字符串精确匹配数值字段,导致 `"123"` 与 `"123.00"` 比较失败;本文详解通过类型标准化、逻辑比较模式或自定义 `comparator` 实现语义等价校验,无需忽略字段。
在使用 JSONAssert.assertEquals() 进行 JSON 响应断言时,一个常见痛点是:当预期 JSON 中的数值字段(如 "balance": "123")以字符串形式存在,而实际响应返回 "balance": "123.00" 时,即使二者数学语义等价,断言仍会失败——因为默认采用严格字符串比对(strict mode),不进行类型解析或数值归一化。
✅ 推荐方案:启用逻辑比较(Logical Comparison)
JSONAssert 提供了非严格模式(strict = false),但仅设置 false 并不足以解决字符串型数字的语义比较问题。真正起效的是 JSONCompareMode.LENIENT 或 JSONCompareMode.NON_EXTENSIBLE 配合数值类型标准化:
- ✅ 正确做法:将 balance 字段在 JSON 中定义为原始数值类型(number),而非字符串:
{ "id": "1234567", "balance": 123 }或
{ "id": "1234567", "balance": 123.00 }此时调用:
JSONAssert.assertEquals(expectedJson, actualJson, JSONCompareMode.LENIENT);
即可自动将 123 与 123.00 视为相等(底层调用 Double.equals() 进行数值比较)。
⚠️ 注意:若 JSON 字符串中 balance 仍被双引号包裹(即 "balance": "123"),JSONAssert 会将其视为字符串,不会自动解析为数字——这是关键误区。务必确保测试用的 expected 和 actual JSON 中该字段是无引号的合法 JSON number。
? 自定义 Comparator(当无法修改 JSON 结构时)
若受制于外部接口或遗留格式,balance 必须以字符串形式存在(如 "123" / "123.00"),则需注入自定义比较逻辑:
import org.skyscreamer.jsonassert.JSONAssert;
import org.skyscreamer.jsonassert.comparator.CustomComparator;
import org.skyscreamer.jsonassert.comparator.JSONComparator;
import static org.skyscreamer.jsonassert.JSONCompareMode.NON_EXTENSIBLE;
// 定义 balance 字段的数值语义比较器
JSONComparator comparator = new CustomComparator(
NON_EXTENSIBLE,
new Customization("balance", (o1, o2) -> {
try {
float f1 = Float.parseFloat((String) o1);
float f2 = Float.parseFloat((String) o2);
return Float.compare(f1, f2);
} catch (NumberFormatException e) {
return ((String) o1).compareTo((String) o2); // 回退到字符串比较
}
})
);
JSONAssert.assertEquals(expectedJson, actualJson, comparator);
该方案精准作用于 balance 字段,保留其他字段的默认校验行为,且兼容异常防护(如非法数字格式)。
? 总结与最佳实践
- 首选:统一 JSON Schema 中数值字段为 number 类型,并在测试数据中使用无引号数值字面量(123 而非 "123"),配合 JSONCompareMode.LENIENT。
- 次选:使用 CustomComparator 对特定字符串型数值字段做 parseFloat + Float.compare() 语义比对。
- 避免:依赖 strict = false 却仍传入字符串型数字——这不会触发数值解析。
- 延伸建议:在 API 设计阶段,通过 OpenAPI/Swagger 明确定义 balance 为 type: number,从源头规避字符串歧义。
通过上述任一方式,即可让 JSONAssert 正确识别 5 与 5.00 的数值等价性,提升断言鲁棒性与测试可维护性。










