当前位置:首页 > 焦点

白盒测试的测试方法

去年帮一个团队排查支付对账的白盒 bug,代码逻辑看起来完全正确,测试但线上就是试方偶尔少几毛钱。后来有人写了个测试,白盒把金额计算函数的测试每个分支都跑了一遍,才发现当金额为 0.1 元且汇率精度截断时,试方某个 if 分支走了意料之外的白盒路径。这就是测试白盒测试的典型场景——你盯着代码内部结构设计用例,而不是试方只看输入输出对不对。

白盒测试的白盒核心就一句话:测试用例来自代码逻辑,不是测试来自需求文档。需求文档告诉你“转账要扣手续费”,试方代码告诉你“手续费 = 金额 × 费率,白盒但金额小于 1 元时费率为 0”。测试白盒测试要覆盖的试方是后面这层东西。

语句覆盖:最弱但最常用

语句覆盖就是让每一行可执行代码至少跑一次。写起来简单,工具一插桩就能看到哪行没跑到。但它有个大坑:if (a && b) 这种条件,你只要让 a 和 b 同时为真,语句就覆盖了,可 a 为真 b 为假的情况根本没测到。我见过太多项目拿语句覆盖率当 KPI,冲到 90% 以上,结果线上还是炸——因为分支逻辑压根没走全。

判定覆盖和条件覆盖:拆开看

判定覆盖要求每个判断的真假分支都走一遍。还是那个 if (a && b),你得设计两组数据:一组让整个条件为真,一组为假。但条件覆盖更进一步,它要求 a 和 b 各自取真取假都出现。这两者经常被混着用,实际项目里我习惯先看判定覆盖,如果条件之间有关联(比如 a 为假时 b 根本不会计算),再补条件组合。

举个例子。一个权限校验函数:

if (user.role === 'admin' || user.department === 'finance') {  return true; } return false; 

判定覆盖只需要两组用例:admin 用户、非 admin 且非 finance 用户。但条件覆盖要求你测到“非 admin 但 finance”的情况——这个用例很可能暴露一个业务漏洞:财务部普通员工到底该不该有权限?代码写了或运算,需求可能只想要与运算。

路径覆盖:组合爆炸的现实

路径覆盖想穷举所有可能的执行路径。一个函数里三个连续的 if,理论上有 2³ = 8 条路径。十个 if 呢?1024 条。所以实际没人真做全路径覆盖,而是挑关键路径。我的做法是:先画控制流图,找出环路复杂度,那个数字就是需要覆盖的基本路径数。环路复杂度 5,就设计 5 条独立路径的用例,够用且不冗余。

有个细节值得说:循环结构让路径数量变成无限。一个 while 循环,你可以跑 0 次、1 次、2 次……白盒测试里通常只测 0 次、1 次、典型次数、边界次数。别想着穷举,那是跟自己过不去。

条件组合覆盖的取舍

条件组合覆盖要求每个判断里所有条件的真假组合都出现。三个条件就是 8 种组合。听起来不多,但函数里往往有多个判断,组合数相乘就爆了。我的经验是:只对安全相关、金额计算、权限校验这三类代码做条件组合覆盖,其他业务逻辑用判定覆盖加边界值就够了。工具能自动生成组合用例,但生成的用例往往不可读,维护成本高,得权衡。

白盒测试有个天然局限:它验证代码做了你让它做的事,不验证代码做了需求要它做的事。你写了个排序函数,白盒测试全绿,但需求要的是降序,你写成了升序——白盒测不出来。所以它永远得和黑盒测试搭配着用。工具方面,Java 用 JaCoCo,JS 用 Istanbul,Python 用 coverage.py,插桩跑一遍,覆盖率报告直接告诉你哪行没测到。但记住,覆盖率是手段不是目的。100% 语句覆盖的代码照样可能有 bug,我上面说的那个支付对账问题,语句覆盖率就是 100%。

真正有用的做法是:拿到覆盖率报告后,专门去看那些没被覆盖的分支,问自己“为什么这行没跑到?是死代码,还是测试用例设计漏了?”这个追问的过程,比覆盖率数字本身值钱得多。

分享到: