第一章:代码覆盖率详解
各位同学好,我是你们的老朋友。今天咱们聊聊代码覆盖率——这个看似基础、实则暗藏玄机的话题。
说实话,我见过太多团队把覆盖率当成KPI来追。90%的行覆盖率,听起来很美。但上线后呢?该崩还是崩。为什么?因为行覆盖率只是冰山一角。
我个人习惯把覆盖率比作「探照灯」。你照到的地方,不一定安全;但你没照到的地方,一定危险。今天我们就来拆解这五盏探照灯:行覆盖率、分支覆盖率、条件覆盖率、路径覆盖率、函数覆盖率。
1. 行覆盖率:最基础的体检
行覆盖率,也叫语句覆盖率。说白了就是:你的测试用例执行了多少行代码。
计算公式: 已执行行数 / 总可执行行数 × 100%
举个例子:
def calculate_discount(price, is_vip):
if is_vip: # 第1行
return price * 0.8 # 第2行
return price # 第3行
如果你只测了 is_vip=True 的情况,行覆盖率是 2/3 ≈ 66.7%。
嗯,这里要注意。行覆盖率达标不代表代码没问题。我在项目中遇到过,行覆盖率冲到95%,结果线上出了个空指针异常。为什么?因为那5%没覆盖到的行,恰好是异常处理逻辑。
我的建议: 行覆盖率可以作为「最低门槛」,但别把它当圣旨。我个人习惯把行覆盖率定在80%以上,剩下的精力去补其他覆盖率。
2. 分支覆盖率:把岔路口走一遍
分支覆盖率关注的是代码中的「岔路口」——if/else、switch/case 这些。
你想想看,一个简单的 if-else,就有两个分支。你的测试用例走了 if 分支,但 else 分支呢?
if (age >= 18) {
// 成年人逻辑
} else {
// 未成年人逻辑
}
分支覆盖率要求:每个分支至少被执行一次。
| 测试用例 | 覆盖的分支 | 分支覆盖率 |
|---|---|---|
| age=20 | if 分支 | 50% |
| age=15 | else 分支 | 50% |
| 两个都测 | 两个分支 | 100% |
避坑指南: 我曾经吃过一个亏。一个 switch 有5个 case,我测了4个,漏了一个 default。结果用户输入了非法值,程序直接崩了。从那以后,我要求团队:分支覆盖率必须100%,包括 default。
3. 条件覆盖率:把每个条件拆开看
条件覆盖率比分支覆盖率更细。它关注的是每个布尔条件的真假值。
举个例子:
if (a > 0 && b < 10) {
// do something
}
分支覆盖率只关心 if 和 else 两个分支。但条件覆盖率要求:a > 0 要取 true 和 false,b < 10 也要取 true 和 false。
说白了,条件覆盖率是「显微镜模式」。它能把复合条件拆成原子条件,逐个验证。
关键区别: 分支覆盖率看的是「路」,条件覆盖率看的是「灯」。路走了不代表每个灯都亮了。
我个人习惯在关键业务逻辑上,强制要求条件覆盖率。比如支付金额计算、权限校验这些地方,条件覆盖率不到100%,我不放心上线。
4. 路径覆盖率:最严格,也最昂贵
路径覆盖率要求:覆盖代码中所有可能的执行路径。
你想想看,如果有3个 if-else,理论上就有 2³ = 8 条路径。如果嵌套更深,路径数会指数级增长。
if (x > 0) {
// A
}
if (y > 0) {
// B
}
if (z > 0) {
// C
}
这里有 2³ = 8 条路径。路径覆盖率要求每条路径都走一遍。
现实问题: 路径覆盖率在实际项目中很难做到100%。我记得有个项目,核心模块有20个条件分支,路径数超过100万条。真要全覆盖,测试用例能跑到天荒地老。
我的做法是:对核心模块、高频调用路径做路径覆盖。其他模块,用分支覆盖+条件覆盖来兜底。
5. 函数覆盖率:从宏观视角看
函数覆盖率最简单:你的测试用例调用了多少个函数。
公式:已调用函数数 / 总函数数 × 100%
这个指标适合做「快速扫描」。我经常用它来发现「僵尸函数」——那些写了但没人调用的函数。
实用技巧: 函数覆盖率可以帮你发现「死代码」。我曾经在一个老项目中,用函数覆盖率发现了一个没人调用的支付回调函数。一问才知道,那是三年前废弃的逻辑,一直没人清理。
五种覆盖率对比总结
| 覆盖率类型 | 关注点 | 严格程度 | 实际应用 |
|---|---|---|---|
| 行覆盖率 | 每行代码是否执行 | ★☆☆☆☆ | 基础门槛,快速评估 |
| 分支覆盖率 | 每个分支是否走到 | ★★☆☆☆ | 日常测试,必须达标 |
| 条件覆盖率 | 每个布尔条件真假 | ★★★☆☆ | 关键逻辑,重点覆盖 |
| 路径覆盖率 | 所有路径组合 | ★★★★★ | 核心模块,选择性覆盖 |
| 函数覆盖率 | 函数是否被调用 | ★☆☆☆☆ | 宏观扫描,发现死代码 |
最后说一句:覆盖率是手段,不是目的。别为了凑数字去写无意义的测试用例。好的测试用例,应该像狙击手——精准、高效、直击要害。
嗯,这一章就到这里。记住这五种覆盖率,后面我们会讲怎么用它们来指导用例设计。