单元测试中的代码覆盖率(Code Coverage in Unit Test)


徐佳莹-不痛
Tessy_Coverage_viewer.jpg

What is code coverage

代码覆盖率(code coverage,test coverage)是单元测试(unit test)中的一种度量方法,用来评估测试用例(test case)能够覆盖多少的代码,能够从一定程度上反应代码的质量。可以用公式来表示:
Code Coverage=(Number of items excuted)/(Total Number of Items)*100%

how many types of code coverage

Function Coverage

用来指示是否所有的函数都被调用过。

Statement Coverage(SC,C0)

语句覆盖率(statement coverage,SC),也称为行覆盖率(line coverage),反映了语句(汇编级指令或C语言的语句)的执行率。通常记为:C0。

Code excerpt to illustrate the weakness of statement coverage
1
2
3
4
5
6
int a = 0;
if (decision)
{
a = 1;
}
a = 1 / a;

test case:decision = 1,则所有语句均会执行一次,覆盖率为100%,但是如果decision是’0’,那么执行这段代码出现除0错误。
所以,即使是100%的state coverage,也有可能会有严重的bug存在。
100%的SC仅仅意味着:所有语句在测试中至少被执行了一次,仅此而已。
SC可以用来指示dead code,这些code根本不能被执行;
SC可以说明需要增加test case。

Branch Coverage / Decision Coverage (DC,C1)

定义:是否每个控制结构(如if,case语句)的所有branch都被执行过。
同样上一节的代码,decision为’1’的DC只有50%,因为if隐含的else没有被执行过;如果需要达到100%的DC,至少再增加decision为 ‘0’的测试用例。
DC包含SC,如果100%的DC则肯定是100%的SC。
但如果是50%的DC并不能说明是50%的SC。因为DC是计算decision的分支,如if语句只可能是0%,50%或100%三种覆盖率,无其他可能;而SC是计算语句执行的百分比。
有时候100%的Branch Coverage不可能达到。

Condition Coverage(CC)

定义:是否每个布尔子表达式都被估值过true和false。

A decision can be made up of conditions
1
if ((A||B)&&(C||!D))

(A||B)&&(C||!D)是一个decision,但是由A、B、C和D四个condition(atomic decision)组成。

Simple CC

A code snippet in Pascal and the four possible test cases (complete evaluation)
1
2
3
4
IF A AND B THEN
...
ELSE
...
A B A and B
1 F F F
2 F T F x
3 T F F x
4 T T T

由于Pascal逻辑运算没有短路,而是complete evaluation,所以只需要执行test case2和3就能达到Simple CC 100%的覆盖率(A和B都执行过true和false);但此时DC才达到50%。

再举一例

A code snippet in C and the three possible test cases (incomplete evaluation)
1
2
3
4
5
6
7
8
if (A && B)
{
...
}
else
{
...
}

A B A and B
1 F - F x
2 T F F x
3 T T T x

C语言有短路运算逻辑表达式的,所以需要3个测试用例才能使A和B都执行过true和false,此时CC和DC都是100%.

Modified Condition / Decision Coverage(MC/DC,MCDC)

MC/DC=DC+CC+每个condition能独立影响decision的输出结果。

1
if ((a || b) && c)

a b c ((a or b) and c)
1 F F F F
2 F F T F
3 F T F F
4 F T T T
5 T F F F
6 T F T T
7 T T F F
8 T T T T

Test case 1和8就能够使得DC+CC达到100%。
但是1中的’c’,8中国的’b’不能影响desicion的输出结果不能满足MC/DC的标准。
以下test case能够满足MC/DC的要求:
| | a | b | c | ((a or b) and c) |
|—–|:—:|:—:|:—-:|:—————:|
| 2 | F | F | T | F |
| 3 | F | T | F | F |
| 4 | F | T | T | T |
| 6 | T | F | T | T |

2与6由a独立影响;2与4由b独立影响;3与4由c独立影响。

Multiple Condition Coverage(MCC)

MCC要求一个desicion里的所有condition的组合都要被测试到,也就是说test case由conditon的真值表确定。
如上一节的例子,需要1到8所有的case来达到100%的MCC。

Path Coverage(C4)

路径覆盖率测量所有可能的执行路径中多少路径被执行了。

1
2
if (a) x else y;
if (b) z;

需要4(=22)个test case来达到100%的path coverage。

a b
1 F F x
2 F T x
3 T F x
4 T T x

path coverage所需的test case随着branch的增多而成指数级增加,特别是有循环的话,基本达到100%的覆盖率是不现实的。

用处

  • 一些标准(如:ISO26262 part6)和客户的要求
  • 帮助发现一些未测试的代码块
  • 有助于重构

局限性

100%的代码覆盖率并不意味着没有bug;
代码覆盖率只针对测试的代码,而不是功能规范(functioality specification);
不能为了提高测试覆盖率而忽略主要目的是测试代码的行为(代码行为与设计是不是一致)不能因为修改代码的同时需要修改或增加测试用例来满足覆盖率要求,而放弃了对代码的优化。

Reference:

  1. Is 100% Code Coverage Enough?
  2. code coverage, what is for after all?
  3. hats my Coverage? (C0 C1 C2 C3 + Path)
  4. Code Coverage Does Matter
  5. Code Coverage
  6. Code Coverage Analysis
  7. TestCoverage