测试插入与断言覆盖收敛实战 - 第3节
分支覆盖:定义与原理
分支覆盖,说白了就是测试你的代码里每个判断分支有没有被走到。
我刚开始做测试时,总觉得语句覆盖就够了。后来有一次线上出了个bug,查了半天才发现是某个else分支从来没被执行过。嗯,从那以后我就特别重视分支覆盖了。
分支覆盖的核心思想很简单:
- 每个if-else、switch-case等判断结构
- 每个分支(true和false)至少被执行一次
- 关注的是判断结果,而不是语句本身
一句话总结:分支覆盖保证每个判断的"是"和"否"都跑过一遍。
分支覆盖 vs 语句覆盖
这两个概念经常被混淆。我见过不少团队,说做了全覆盖,其实只是语句覆盖。你想想看,这两者到底差在哪?
| 对比维度 | 语句覆盖 | 分支覆盖 |
|---|---|---|
| 关注点 | 每行代码是否执行 | 每个判断分支是否执行 |
| 覆盖粒度 | 语句级别 | 分支级别 |
| 漏测风险 | 高(可能漏掉分支逻辑) | 低(能发现分支遗漏) |
| 测试用例数 | 较少 | 较多(通常需要2倍以上) |
| 典型场景 | 简单顺序逻辑 | 复杂判断逻辑 |
举个例子你就明白了:
if (x > 0) {
y = 1; // 语句A
} else {
y = -1; // 语句B
}
z = y * 2; // 语句C
如果只做语句覆盖,我只需要让x=1,就能覆盖A和C。但B分支呢?完全没测到。这就是语句覆盖的坑——它不关心else分支。
分支覆盖就不一样了。它要求:
- x > 0 为 true 时(走A分支)
- x > 0 为 false 时(走B分支)
两个分支都得测到。所以至少需要两个用例:x=1 和 x=-1。
我的习惯:做单元测试时,我一般先看分支覆盖。如果分支覆盖都不到80%,语句覆盖再高也没用。说白了,分支覆盖是语句覆盖的"升级版"。
实战案例:计算if-else结构的分支覆盖率
咱们直接上一个真实项目里简化过的例子。这段代码是判断用户订单状态的:
public String getOrderStatus(int orderType, double amount) {
String status;
if (orderType == 1) {
if (amount > 100) {
status = "VIP订单";
} else {
status = "普通订单";
}
} else {
if (amount > 0) {
status = "待支付";
} else {
status = "已取消";
}
}
return status;
}
这段代码里有几个分支?我们来数一数:
- 分支1:orderType == 1 为 true
- 分支2:orderType == 1 为 false
- 分支3:amount > 100 为 true(嵌套在分支1内)
- 分支4:amount > 100 为 false(嵌套在分支1内)
- 分支5:amount > 0 为 true(嵌套在分支2内)
- 分支6:amount > 0 为 false(嵌套在分支2内)
一共6个分支。分支覆盖要求每个分支至少执行一次。
那最少需要几个测试用例?我建议这样设计:
// 用例1:orderType=1, amount=200
// 覆盖:分支1(true)、分支3(true)
// 结果:"VIP订单"
// 用例2:orderType=1, amount=50
// 覆盖:分支1(true)、分支4(false)
// 结果:"普通订单"
// 用例3:orderType=2, amount=10
// 覆盖:分支2(false)、分支5(true)
// 结果:"待支付"
// 用例4:orderType=2, amount=0
// 覆盖:分支2(false)、分支6(false)
// 结果:"已取消"
4个用例,覆盖了全部6个分支。分支覆盖率 = 6/6 = 100%。
我曾经踩过的坑:有一次我自认为写了4个用例就够了,结果漏掉了orderType=1且amount=100的情况(边界值)。虽然分支覆盖是100%,但边界值没测到,线上出了精度问题。所以分支覆盖不是万能的,它只是基础。
分支覆盖率的计算公式
公式其实很简单:
分支覆盖率 = (已执行的分支数 / 总分支数) × 100%
注意:
- 每个if-else算2个分支(true和false)
- 每个switch-case的每个case算1个分支
- 三元运算符 ? : 也算2个分支
- 逻辑运算符 && 和 || 也会产生隐式分支
小技巧:我一般用工具自动统计分支覆盖率。比如JaCoCo、Istanbul这些。手动数太容易漏了,尤其是嵌套if多的时候。
分支覆盖的局限性
说实话,分支覆盖也不是银弹。我遇到过这些情况:
- 条件组合遗漏:分支覆盖只关心每个分支是否执行,不关心多个条件的组合情况。比如 if (a && b),分支覆盖只测a=true和a=false,但a=true,b=true和a=true,b=false的组合可能漏掉。
- 循环边界问题:分支覆盖不关心循环执行了多少次,0次和100次在分支覆盖里是一样的。
- 异常路径:分支覆盖通常不覆盖异常处理分支,需要额外关注。
所以我的建议是:分支覆盖作为最低标准,在这个基础上再补充条件覆盖、路径覆盖等更严格的指标。
核心要点回顾:
- 分支覆盖 = 每个判断分支至少执行一次
- 比语句覆盖更严格,能发现分支遗漏
- 嵌套if的分支数 = 每个if的2个分支累加
- 工具自动统计比手动数更靠谱
- 分支覆盖是基础,但不是全部
好了,分支覆盖这块就聊到这儿。记住一句话:分支覆盖做到100%,不代表代码没bug;但分支覆盖不到100%,一定有代码没测到。