← 回到花园
软件工程 · 长文

覆盖率 98%,为什么还有 7 个失败用例

一次订单处理实验,让覆盖率、断言和需求之间的区别变得很具体。

测试报告里有两个容易被放在一起看的数字:覆盖率和通过率。一次订单处理实验中,前者接近满分,后者却清楚地留下了失败。这两个结果同时成立,也各自有用。

从一条基线测试开始

实验围绕订单处理逻辑展开,包括商品数量、库存、优惠券、会员优惠和地址校验。最初只有一条测试,运行结果为 1 passed。

覆盖报告统计了 50 条语句,其中 12 条没有执行到,语句覆盖率是 76%。这一条通过的测试说明一个具体输入符合预期,却无法回答其他分支会怎样。

我保留了业务实现和原测试,再补充 43 条用例。扩展后的结果是:

阶段 测试结果 未覆盖语句 语句覆盖率
基线 1 passed 12 / 50 76%
扩展 37 passed,7 failed 1 / 50 98%

这是 2026 年 10 月那次实验的记录。它最有价值的部分,是两个数字之间的张力:执行到了更多代码,同时观察到了更多不符合预期的行为。

执行过,不代表算对了

覆盖率关心某段代码是否被执行。断言关心这次执行的结果是否满足预期。

假设某条分支确实被执行了,但它把会员折扣覆盖在优惠券之上,而需求要求的是另一种组合顺序。这条语句仍然会计入覆盖率;只有检查最终金额的断言,才会暴露行为上的差别。

因此,增加测试不只是绕过每个 if。还要问:同一个分支,什么输入会揭示计算错误、类型边界或组合规则的问题?

七个失败,整理成六类问题

实验记录把失败整理为六类:

  • 百分比优惠券在单条目场景中的限制。
  • 会员优惠与优惠券之间的覆盖关系。
  • 布尔值被当成商品数量接收。
  • 同一商品重复出现时,累计数量超过库存。
  • 畸形条目触发解包异常。
  • 地址类型异常时的处理。

它们也提醒我,把失败报告写清楚需要回到需求。已明确规定的金额规则可以直接检查;额外加入的健壮性预期,需要说明依据。不能只因为一个断言失败,就把它无条件写成产品缺陷。

为什么停在 98%

剩下的一条语句是负金额保护。在当时固定的商品数据、券值和会员规则下,不使用 Mock 或修改数据库,就无法构造出进入这条保护分支的输入。

这时应记录“在当前实验约束下不可达”,并解释原因。为了把数字变成 100% 而改变前提,会把另一个实验的问题混进来。

这次实验留下的方法

我会把测试结果分成三层看:

  1. 到达范围:哪些语句或分支执行过,哪些还没覆盖。
  2. 行为判断:断言验证了什么,有没有只检查“运行没报错”。
  3. 需求依据:预期来自明确要求,还是为了探索边界而额外提出的假设。

覆盖率帮助发现盲区,失败用例帮助发现差异,而需求决定该如何解释这些差异。把三者一起看,报告才有下一步。


这篇笔记整理自本人的订单处理白盒测试实验。表中数字保留当时结果,未把失败测试改写成通过。

✳

记于 2026-11-05 · 2026-11-05 更新