生成了测试用例,为什么还是测不出计算错误?

计算类测试首先需要可信的公式与判据,再用能够区分正确和错误算法的数据形成用例。通过合成金额示例,拆解公式获取、独立预期计算和页面执行之间的关系。

发布 ·更新 ·约 15 分钟 ·hugfeature

AI Eval 系列 #13
上一篇:测试用例 Agent 的门禁落地:一条需求缺口,应该挡住哪些用例?

一条计算类测试用例可能写得很完整:进入页面,填写字段,点击计算,检查结果正确。

但如果预期结果只有“计算正确”四个字,执行者仍然不知道应该拿什么判断。即使填了一个具体数字,这个数字也可能来自对页面结果的照抄,或者来自未经确认的公式。

我目前优先关注的是计算公式的获取,以及公式能否成为可信判据。如果“应该算出什么”本身没有依据,增加用例数量很难解决问题。

不过,公式取对以后,还有第二个问题:选取的数据,能不能让错误算法算出不同结果?下面用一个合成示例,把这两层分开。文中的规则、金额和字段均用于说明方法,不对应真实业务,也不代表某个系统已经完成验证。

一、获取公式,要连同适用条件一起获取

需求中出现一行公式,只解决了一部分问题。

例如:“应付金额=优惠后金额+服务费。”它还没有说明优惠作用于哪一层、服务费按什么基数计算,以及在哪一步舍入。

一份可用于测试的计算规则,至少应能回答以下问题:

需要确认的内容 示例问题
变量含义 优惠金额是每件优惠,还是整单优惠?
取值来源 使用用户输入价格,还是价格表中的有效价格?
运算顺序 先优惠再计算服务费,还是反过来?
适用条件 哪些订单参与优惠,哪些订单免服务费?
精度与舍入 中间值是否舍入,最终保留几位,使用哪种规则?
来源及版本 依据哪一版规则,冲突由谁确认?

这些内容可能分散在正文、表格、公式对象、图片和关联说明中。Agent 应记录实际读取到的位置;无法解析某个公式对象时,要暴露读取问题,不能据此断言业务没有定义公式。

公式也不一定以数学表达式出现。明确的自然语言规则可以被转换成表达式,但需要保留转换依据,检查是否增加了原文没有的条件。

原型图能帮助定位字段、按钮和结果区域。只有当原型明确承载了已确认的计算规则时,它才能同时提供判据。 页面上展示了一个金额,并不能单独证明这个金额应当如何计算。

二、三种缺失,需要分别处理

“用例无法执行”不一定意味着“业务判据未知”。

当前缺失 影响 可继续完成的工作
计算公式或适用条件缺失 无法建立受影响部分的确定预期 整理规则问题,保留有依据的独立部分
测试准备数据缺失 暂时无法在目标环境复现输入 基于已确认规则设计数据要求和预期
页面入口或操作路径缺失 暂时无法落实完整操作步骤 保留计算设计,标记执行路径待补

例如,公式已经明确,但测试环境还没有符合条件的订单。此时可以先说明需要什么订单、使用什么字段值、预期如何计算;不能把该用例标为可直接执行,也没有必要把已经明确的公式退回“未知”。

相反,如果只是能够打开页面、填写字段,却没有可信的计算规则,操作路径再完整也无法补上判据。

这种区分能帮助评审者决定下一步是补规则、准备数据,还是确认入口,避免所有问题都进入“重新生成用例”的循环。

三、一个例子:公式正确,数据仍然可能无效

假设有一条已经确认的合成规则:

  • 原始金额=数量 × 单价。
  • 优惠为整单优惠,先从原始金额中扣减。
  • 服务费=优惠后金额 × 服务费率。
  • 应付金额=优惠后金额+服务费。
  • 本例输入均为合法非负值,优惠不超过原始金额;中间不舍入,最终按 ROUND_HALF_UP 保留两位小数。

对应表达式是:

应付金额 = (数量 × 单价 - 整单优惠) × (1 + 服务费率)

先考虑一种可能的实现错误:服务费错误地按优惠前金额计算,优惠放到最后再扣。

错误算法 = 数量 × 单价 × (1 + 服务费率) - 整单优惠

这两个算法的差异来自“优惠金额 × 服务费率”。如果优惠为零,或者服务费率为零,两种算法就会得到相同结果。

数量 单价 整单优惠 服务费率 正确结果 错误算法结果 能否区分这类错误
2 100.00 0.00 10% 220.00 220.00 不能
2 100.00 30.00 0% 170.00 170.00 不能
2 100.00 30.00 10% 187.00 190.00 能

前两组数据可以验证相应场景,但不足以发现这里假设的顺序错误。

第三组数据让差异变得可观察:原始金额为 200.00,优惠后为 170.00,服务费为 17.00,应付金额为 187.00。错误算法则收取 20.00 的服务费,得到 190.00。

这里要检查的已经很具体:这组用例能不能拒绝“优惠前计服务费”这个错误实现。

四、先列一种可能的错误,再选数据

设计计算用例时,可以先针对关键规则列出少量合理的错误假设,再选取能区分它们的数据。

错误假设 选数据时要避免什么
忽略数量,只使用单价 数量始终等于 1
漏减优惠 优惠始终等于 0
服务费基数使用错误 优惠或服务费率始终等于 0
每行舍入后求和,误替代先求和后舍入 所有中间结果都恰好只有两位小数
阶梯规则边界写错 只使用远离阈值的数据

这些是测试设计的候选错误,不是对真实系统缺陷的断言。选出的数据还必须满足已确认的合法输入范围。

这种思路与变异测试有关:PIT 的官方介绍说明,变异测试通过修改程序制造变体,再观察测试能否发现变化。本文只借用“用测试区分正确行为与候选错误行为”的思路;在需求层手工列出错误算法,并不等于已经完成代码级变异测试。

也不需要让每条普通用例都附带一份复杂分析。可以先挑关键计算规则做对照,确认确实改善了检错能力,再决定扩大范围。

五、预期结果需要独立计算,但工具不会替你确认业务规则

对于上面的数据,可以先手工分步计算,再用一个小脚本复核。下面的脚本没有调用被测系统的计算函数:

from decimal import Decimal, ROUND_HALF_UP

quantity = Decimal("2")
unit_price = Decimal("100.00")
discount = Decimal("30.00")
fee_rate = Decimal("0.10")

subtotal = quantity * unit_price
base = subtotal - discount
fee = base * fee_rate
expected = (base + fee).quantize(
    Decimal("0.01"), rounding=ROUND_HALF_UP
)

wrong = (subtotal * (1 + fee_rate) - discount).quantize(
    Decimal("0.01"), rounding=ROUND_HALF_UP
)

assert expected == Decimal("187.00")
assert wrong == Decimal("190.00")
assert expected != wrong
print(expected, wrong)

Python 的 decimal 支持十进制计算,并提供精度和舍入控制;示例用字符串构造输入,显式指定最终舍入方式。真实测试仍需按业务允许的数值范围设置合适精度,不能把这个短脚本直接当成通用金额引擎。

这里的独立性也有边界。脚本能复核给定规则下的算术,不能证明规则本身正确。如果手工计算和脚本都使用了同一个误读的公式,它们仍可能一致地算错。

因此至少要分开核对两件事:

  • 规则依据: 为什么应该先优惠,再计算服务费?
  • 计算过程: 这组输入代入已确认规则,是否确实得到 187.00?

让同一个 Agent 再计算一次,可以作为复查步骤,但不能仅凭第二次回答就宣称完成了独立验证。

六、最后才把计算设计写成可执行步骤

计算设计明确后,才有条件把它落实到页面。仍以上述合成场景为例,假设目标页面已确认包含对应字段:

用例要素 示例内容
目的 发现服务费错误地按优惠前金额计算
前置条件 使用支持整单优惠与服务费的订单;无其他折扣、费用或自动改价规则
数据 数量=2;单价=100.00;整单优惠=30.00;服务费率=10%
操作 在已确认的订单入口填写上述字段,触发计算
预期 应付金额=187.00;若页面展示优惠后金额与服务费,则分别核对 170.00 和 17.00
规则依据 关联已确认规则的位置与版本

真实用例需要把“已确认的订单入口”替换为实际可定位的路径,并核对输入控件如何表达 10%:页面可能要求输入 10,也可能使用 0.10,不能把脚本表示直接复制成页面操作。

同样,产品未展示中间金额时,不应凭空增加页面断言。是否通过接口或其他可观测位置核对中间值,需要结合实际测试入口确定。

字段和值、计算过程和观察位置都明确后,执行者才知道怎样操作,以及出现什么结果算失败。

七、改进 Agent 时,先做一个有界对照

如果希望让生成器更重视计算设计,可以先试验一条指导:

对范围内的关键计算规则,核对来源和适用条件;提出一种可能的错误算法,选择能使其与正确规则产生不同结果的合法数据,独立计算预期,再落实到已确认的执行入口。缺失内容分别记录。

这条指导只是候选改法,效果需要验证。

一次对照可以固定输入、范围、模型配置和其他指导,只调整计算设计要求,再比较:

  1. 公式及适用条件是否有可核对的来源。
  2. 具体预期是否可复算,是否出现编造规则。
  3. 在相同候选错误集合下,测试数据能否暴露更多错误。
  4. 用例是否能够落实到实际字段、操作和观察位置。

如果要检验“公式获取”的改进,应另外安排输入解析或规则提取的对照。把提取方式、生成指导和评审规则同时改掉,即使结果变好,也很难解释是哪一项起作用。

即便一轮结果改善,也只能说明这次样本上的表现。应继续保留未改善样本和典型失败,再决定是否推广。

我会先看公式与判据能否站得住,再看数据是否有区分度。前者决定预期的依据,后者决定用例能否暴露所针对的计算错误;两者都需要落到可检查的产物上。

八、动手复现:漏掉税率的百分数换算

为了让读者实际运行,附上一个独立于前文服务费示例的税率换算样例。这里的输入范围、异常处理和税率都是合成教学约定,不代表真实税务规则。

样例约定:金额为不含税金额,输入税率 13 表示 13%;税额等于金额乘税率再除以 100,最终按 ROUND_HALF_UP 保留两位小数。故意错误的实现只漏掉“除以 100”。

输入金额 输入税率 固定预期税额 错误实现结果 作用
100 13 13.00 1300.00 检出百分数换算错误
0 13 0.00 0.00 说明零金额无法区分该错误
100 0 0.00 0.00 说明零税率无法区分该错误
0.05 10 0.01 0.50 检查舍入,并检出换算错误

例如第一行可独立复算:13% = 0.13,100 × 0.13 = 13.00。预期值固定保存在 CSV 中,执行时不会调用被测函数来生成预期。

下载以下四个文件,放在同一个目录:

使用 Python 3.9 或更高版本,无需安装第三方依赖:

python check.py
python check.py --mutant

本次实际运行结果:正常实现 23/23 通过;漏掉“÷100”的错误实现有 6 条失败,退出码为 1。后者是预期的检错结果。零金额与零税率仍通过,说明通过数量不能代替数据区分能力。

异常数据覆盖了空值、文本、负数、范围、精度及不支持的输入格式。负金额在本样例中被明确拒绝;真实业务若允许退款,应先确认规则,再修改用例,不能照搬。错误实现复用了相同输入校验,异常用例通过并不能证明它们检出了校验缺陷。

复用时,先确认自己的公式、字段含义和异常规则,再替换脚本中的 calculate 为实际函数或接口适配。这个包验证的是一个计算示例,没有连接真实页面,也没有证明完整税务流程正确。

参考与继续阅读

继续阅读这个系列

AI Eval:从大模型评测到 Agent Reliability →
展开完整系列目录(13 篇)
  1. 大模型评测到底在评什么?Benchmark、Eval、业务评测一次讲清
  2. 排行榜第一,为什么到了你的业务里可能不好用?
  3. Model Eval 和 Agent Eval 有什么区别?从单次输出到完整执行轨迹
  4. 怎样构造一套真正有用的业务 Eval Dataset?
  5. LLM-as-a-Judge 怎么做才靠谱?从 Rubric、偏差到人工校准
  6. Eval 指标怎么设计?为什么 Pass Rate 远远不够
  7. Offline Eval 和 Online Eval 有什么区别?一套 AI 系统为什么两个都需要
  8. 线上失败怎么变成 Failure Corpus?从一次事故到持续回归
  9. Agent Trace Grading 怎么设计?结果正确,过程也可能已经失控
  10. 怎么把 AI Eval 接进 CI / Quality Gate?让评测真正阻断坏版本
  11. 需求不完整时,测试用例生成的 Gate 应该怎么判?
  12. 测试用例 Agent 的门禁落地:一条需求缺口,应该挡住哪些用例?
  13. 生成了测试用例,为什么还是测不出计算错误? · 当前篇

沿着问题继续探索

从执行机制走向验证与交付。

相关文章

在 GitHub 反馈 ↗