测试插入与断言覆盖收敛实战 - 第4节
条件覆盖:定义与原理
条件覆盖,说白了就是要把每个判断条件里的原子条件都测一遍。
什么叫原子条件?我举个例子:
if (a > 0 && b < 10) {
// 业务逻辑
}
这里 a > 0 是一个原子条件,b < 10 是另一个。条件覆盖要求:每个原子条件至少取一次 true、一次 false。
我个人习惯把条件覆盖理解成「拆到不能再拆为止」。你想想看,如果只做判定覆盖,可能只测了 true 和 false 两种组合,但内部的条件到底谁在起作用?不知道。
我在项目中遇到过这样的坑:一个复杂的权限校验逻辑,判定覆盖全过了,结果上线后某个角色死活进不去某个页面。一查,原来是某个子条件从来没被触发过 false 分支。
核心要点:条件覆盖关注的是每个原子条件的真值变化,而不是整个表达式的最终结果。
条件覆盖的粒度
这里有个容易混淆的点——粒度问题。
条件覆盖的粒度,取决于你怎么定义「原子条件」。一般来说:
- 关系表达式:如
a > 0、name == "admin",每个算一个原子条件 - 布尔变量:如
isActive、flag,每个算一个 - 函数返回值:如
checkStatus(),通常也视为一个原子条件
嗯,这里要注意:不要过度拆分。比如 a > 0 && b < 10 里的 a > 0 本身就是一个整体,你没必要再拆成 a 和 0 的比较操作。
| 覆盖类型 | 粒度 | 测试用例数(典型) |
|---|---|---|
| 语句覆盖 | 最粗 | 1~2 |
| 判定覆盖 | 中等 | 2 |
| 条件覆盖 | 较细 | 2~n(n为原子条件数) |
| 条件/判定覆盖 | 更细 | 2~n |
| MC/DC | 最细 | n+1 |
从表格能看出来,条件覆盖的测试用例数跟原子条件数量直接相关。条件越多,用例越多。
我的经验:实际项目中,条件覆盖通常用在关键模块的接口层或核心算法上。全量条件覆盖成本太高,我一般建议「核心路径全覆盖,非核心路径抽样」。
实战案例:计算复合条件的条件覆盖率
光说不练假把式。我们来看一个真实的例子。
被测代码
public boolean canAccess(String userType, int level, boolean isVip) {
// 复合条件:三种原子条件组合
if ((userType.equals("admin") || level >= 5) && isVip) {
return true;
}
return false;
}
这里有三个原子条件:
- A:
userType.equals("admin") - B:
level >= 5 - C:
isVip
条件覆盖要求
每个原子条件至少取一次 true、一次 false。所以我们需要:
- A 为 true 的用例 + A 为 false 的用例
- B 为 true 的用例 + B 为 false 的用例
- C 为 true 的用例 + C 为 false 的用例
最少需要多少用例?理论上 2 个就够了,但实际往往需要更多。
设计测试用例
| 用例编号 | userType | level | isVip | A | B | C | 结果 |
|---|---|---|---|---|---|---|---|
| TC1 | "admin" | 3 | true | true | false | true | true |
| TC2 | "user" | 6 | false | false | true | false | false |
检查一下:
- A: TC1=true, TC2=false ✅
- B: TC1=false, TC2=true ✅
- C: TC1=true, TC2=false ✅
两个用例就实现了 100% 条件覆盖!
条件覆盖率 = (已覆盖的原子条件真值组合数 / 总原子条件真值组合数) × 100%
本例:6个真值组合(3个条件 × 2个值),全部覆盖,覆盖率 100%。
条件覆盖率的计算过程
实际项目中,我们通常用工具来算。但手工算一遍有助于理解:
- 列出所有原子条件:A、B、C
- 列出每个条件的真值表:A(true/false)、B(true/false)、C(true/false)
- 统计已覆盖的真值:每个条件至少有一个 true 和一个 false
- 计算覆盖率:已覆盖的真值数 / 总真值数
我曾经在一个金融项目中,用条件覆盖发现了支付网关的一个隐藏 bug。那个条件表达式有 5 个原子条件,判定覆盖只用了 2 个用例就过了,但条件覆盖需要至少 6 个用例。结果第 4 个用例就暴露了问题——某个边界条件下,手续费计算逻辑走错了分支。
注意:条件覆盖 ≠ 判定覆盖。条件覆盖 100% 不代表判定覆盖 100%。比如上面的例子,如果只测 TC1 和 TC2,判定覆盖只有 50%(只覆盖了 true 和 false 各一次,但判定结果只有 true 和 false 两种,实际上两个都覆盖了,所以判定覆盖也是 100%——这里要小心,条件覆盖和判定覆盖的覆盖对象不同,不能直接等价)。
条件覆盖的局限性
说实话,条件覆盖也不是万能的。它有个明显的短板:不保证覆盖所有条件组合。
比如上面的例子,虽然每个原子条件都覆盖了 true/false,但组合情况呢?A=true & B=true & C=true 这种组合就没测到。如果这个组合会触发某个特殊逻辑,那就漏了。
所以实际工作中,我通常把条件覆盖作为基础要求,再结合判定覆盖、MC/DC 来补全。别指望一招鲜吃遍天。
知识体系总览
下面这张图帮你理清条件覆盖在整个测试覆盖体系中的位置:
条件覆盖是测试覆盖技术中承上启下的一环。它比判定覆盖更细,但又不像 MC/DC 那样严格。说白了,它就是让你确保每个小条件都被「折腾」过——既当过 true,也当过 false。
我在写测试用例时,习惯先列原子条件清单,再设计用例。这样不容易漏。你也可以试试这个方法。
实用技巧:用 Excel 或思维导图列出所有原子条件,然后打勾确认每个条件都有 true 和 false 的用例。视觉化之后,漏掉的情况一目了然。
可可精品资料库