单元测试覆盖率是衡量测试代码对应用代码覆盖程度的指标,常用的覆盖率指标包括 statements(语句)、branches(分支)、functions(函数) 和 lines(行)。以下是这些指标的具体含义:
1. Statements(语句覆盖率)
- 定义:统计被执行的代码语句占总语句的比例。
- 示例:
1
2
3
4function sum(a, b) {
const result = a + b; // 语句1
return result; // 语句2
}- 覆盖率计算:若测试执行了
sum(1, 2)
,则两条语句均被执行,语句覆盖率为 100%。
- 覆盖率计算:若测试执行了
2. Branches(分支覆盖率)
- 定义:统计代码中每个条件分支(如
if/else
、三元运算符、switch
)是否被执行。 - 示例:
1
2
3
4
5
6
7function checkNumber(n) {
if (n > 0) { // 分支1:true/false
return 'positive'; // 分支1-true
} else {
return 'non-positive'; // 分支1-false
}
}- 覆盖率计算:
- 若测试仅执行
checkNumber(1)
,则只覆盖了n > 0
为true
的分支,分支覆盖率为 50%。 - 若测试同时执行
checkNumber(1)
和checkNumber(-1)
,则覆盖所有分支,分支覆盖率为 100%。
- 若测试仅执行
- 覆盖率计算:
3. Functions(函数覆盖率)
- 定义:统计代码中每个函数是否被调用。
- 示例:
1
2function add(a, b) { return a + b; } // 函数1
function multiply(a, b) { return a * b; } // 函数2- 覆盖率计算:
- 若测试仅调用
add(1, 2)
,则函数覆盖率为 50%。 - 若测试同时调用
add(1, 2)
和multiply(2, 3)
,则函数覆盖率为 100%。
- 若测试仅调用
- 覆盖率计算:
4. Lines(行覆盖率)
- 定义:统计被执行的代码行占总行数的比例。
- 示例:
1
2
3
4
5
6
7function calculate(n) {
if (n > 0) { // 行1
return n * 2; // 行2
} else {
return n / 2; // 行3
}
}- 覆盖率计算:
- 若测试仅执行
calculate(1)
,则行覆盖率为 67%(行1和行2被执行,行3未执行)。 - 若测试同时执行
calculate(1)
和calculate(-1)
,则行覆盖率为 100%。
- 若测试仅执行
- 覆盖率计算:
为什么需要关注这些指标?
- 语句覆盖率:确保代码中的每一行都被执行,但可能遗漏分支逻辑。
- 分支覆盖率:验证所有条件分支是否被测试,避免逻辑漏洞(如
if/else
只测了一种情况)。 - 函数覆盖率:确保所有函数都被调用,避免未使用或未测试的代码。
- 行覆盖率:与语句覆盖率类似,但可能受代码格式影响(如一行包含多个语句)。
示例对比
假设代码如下:
1 | function isAdult(age) { |
测试用例1:
isAdult(20)
- 语句覆盖率:100%(两行都执行)
- 分支覆盖率:50%(只覆盖了
age >= 18
的true
分支,未覆盖false
分支)
测试用例2:
isAdult(20)
和isAdult(15)
- 语句覆盖率:100%
- 分支覆盖率:100%(覆盖了
age >= 18
的true
和false
分支)
最佳实践
- 优先关注分支覆盖率:它能发现条件逻辑中的潜在漏洞。
- 结合多种覆盖率指标:单一指标无法全面评估测试质量。
- 避免过度追求100%覆盖率:某些代码(如错误处理、边缘情况)可能难以或无需测试。
工具支持
常见的覆盖率工具(如 Istanbul、Jest、Cobertura)会生成详细的覆盖率报告,展示各项指标的覆盖情况。例如:
1 | ----------------------------|---------|----------|---------|---------|------------------- |
通过分析这些指标,你可以针对性地补充测试用例,提高测试质量。