一、业务场景痛点
在接口压测、自动化接口校验中,同个金额字段JE因后端数据库不同,返回格式不一致:
- 达梦数据库:
"JE":6208(整数) - Oracle 数据库:
"JE":6208.0 / "JE":6208.00(1 位 / 2 位小数)
使用JMeter 原生 JSON 断言会出现匹配失败:
- 预期值填
6208,实际6208.00→ 字符串不一致,断言失败; - 预期值填
6208.0,实际6208→ 同样匹配报错; - 开启正则匹配
^6208(\.0+)?$,JSON 断言对 Number 类型 JSON 值存在原生匹配 BUG,依然偶现失败。
同时业务需要根据单据编号变量DJBH1动态筛选指定行数据 ,原 JSONPath 表达式:$.data[?(@.DJBH=="${DJBH1}")].JE,原生断言无法做数值运算适配,因此改用JSR223 Groovy 断言实现统一兼容校验。
二、原 JSONPath 逻辑说明
$.data[?(@.DJBH=="${DJBH1}")].JE
$.data:定位 JSON 顶层 data 数组;[?(@.DJBH=="${DJBH1}")]:过滤数组中DJBH字段等于 JMeter 变量${DJBH1}的单行数据;.JE:提取该行金额字段,是我们需要断言的目标值。
三、JSR223 Groovy 断言实现方案
3.1 操作步骤
- 目标 HTTP 取样器右键 → 添加 → 断言 → JSR223 Assertion;
- 脚本语言选择:
groovy; - 清空默认内容,粘贴下述代码。
3.2 完整通用脚本
groovy
import groovy.json.JsonSlurper
//1.解析接口返回JSON报文
def json = new JsonSlurper().parseText(prev.getResponseDataAsString())
//2.获取JMeter中预存的单据编号变量DJBH1
def targetDJBH = vars.get("DJBH1")
//3.筛选DJBH等于变量的行,等价原JSONPath过滤逻辑
def targetRow = json.data.find{it.DJBH == targetDJBH}
//4.取值并统一转为Double,自动兼容整数、1位小数、2位小数
def realJE = targetRow?.JE as Double
//5.配置预期金额,按需修改
def expectJE = 6208
//6.断言逻辑:找不到数据 或 金额差值超0.01则失败
if(realJE == null || Math.abs(realJE - expectJE) > 0.01){
AssertionResult.setFailure(true)
AssertionResult.setFailureMessage("单据${targetDJBH}金额校验失败:实际值=${realJE},预期值=${expectJE}")
}
3.3 核心原理
- 类型统一 :
as Double将6208、6208.0、6208.00全部转为浮点数字,从数值层面对比,彻底规避字符串格式差异; - 容错处理 :
targetRow?.JE安全导航写法,筛选不到单据时不会空指针异常; - 容差设计 :
Math.abs(差值)>0.01,规避 Java 浮点运算精度 BUG(如 6208.0000000001); - 变量联动 :
vars.get("DJBH1")读取 JMeter 上下文变量,和原 JSONPath 变量用法完全一致。
四、脚本灵活修改说明
- 修改目标变量 :若单据变量从
DJBH1改为DJBH,仅修改vars.get("DJBH1")→vars.get("DJBH"); - 修改预期金额 :仅改动
def expectJE = 6208后的数字; - 修改 JSON 层级 :若 JE 不在
data下,调整json.data.find为对应层级,和 JSONPath 改层级逻辑一致。
五、方案优势总结
- 全格式兼容:整数 / 1 位小数 / 2 位小数三种数据库返回格式全部通过;
- 稳定性更强:脱离 JMeter 原生 JSON 断言字符串匹配缺陷,不受 JSON 字段数据类型(Number)限制;
- 可读性高:失败提示输出单据号、实际值、预期值,排查问题效率远高于原生断言;
- 拓展方便:后续如需多字段联合断言、动态传参预期值,可直接在 Groovy 脚本扩展。
六、拓展:极简精简版脚本(快速部署)
如需快速使用,可选用精简代码,功能完全一致:
groovy
def json = new groovy.json.JsonSlurper().parseText(prev.responseDataAsString())
def djbh = vars.get("DJBH1")
def je = json.data.find{it.DJBH==djbh}?.JE as Double
def exp = 6208
if(Math.abs((je?:0)-exp)>0.01) AssertionResult.setFailure(true,"单据${djbh}金额异常:实际${je}预期${exp}")