测试插入与断言覆盖收敛实战 - 第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%,一定有代码没测到。

可可精品资料库