代码覆盖率测试反映了测试的广度与深度,量化了测试和开发质量,是十分有必要的,业界目前有针对各种语言的覆盖率测试工具,本文主要介绍C/C++
相关的覆盖率测试工具Gcov
介绍
简介
Gcov
是一个测试覆盖程序,是集成在GCC
中的,随GCC
一起发布
基本概念
基本块BB
基本块指一段程序的第一条语句被执行过一次后,这段程序中的每一跳语句都需要执行一次,称为基本块,因此基本块中的所有语句的执行次数是相同的,一般由多个顺序执行语句后边跟一个跳转语句组成
跳转ARC
从一个BB
到另外一个BB
的跳转叫做一个ARC
,要想知道程序中的每个语句和分支的执行次数,就必须知道每个BB
和ARC
的执行次数
程序流图
如果把BB
作为一个节点,这样一个函数中的所有BB
就构成了一个有向图,要想知道程序中的每个语句和分支的执行次数,就必须知道每个BB
和ARC
的执行次数,根据图论可以知道有向图中BB
的入度和出度是相同的,所以只要知道了部分的BB
或者ARC
大小,就可以推断所有的大小,这里选择由ARC
的执行次数来推断BB
的执行次数,所以对部分ARC
插桩,只要满足可以统计出来所有的BB
和ARC
的执行次数即可
原理
测试程序首先进行编译预处理,生成汇编文件,并完成插桩,插桩的过程中会向源文件的末尾插入一个静态数组,数组的大小就是这个源文件中桩点的个数,数组的值就是桩点的执行次数,每个桩点插入3~4条汇编语句,直接插入生成的*.s
文件中,最后汇编文件经过汇编生成目标文件,在程序运行过程中桩点负责收集程序的执行信息
使用
编译
测试代码如下:say.c
:
1 | #include <stdio.h> |
main.c
1 | #include <stdio.h> |
添加-fprofile-arcs -ftest-coverage -fPIC
编译参数编译程序,生成可执行程序和*.gcno
文件,里面记录了行信息和程序流图信息:
1 | $ gcc -fprofile-arcs -ftest-coverage -fPIC -O0 say.c main.c |
数据收集
运行可执行文件,生成*.gcda
在默认生成在相应*.o
文件目录,里面记录了*.c
文件中程序的执行情况,包括跳变次数等:
1 | $ ./a.out |
可以通过设置环境变量GCOV_PREFIX=/xxx/xxx
和GCOV_PREFIX_STRIP=x
来改变路径,其中GCOV_PREFIX_STRIP
表示去掉源代码路径中的前几级,默认为0
,比如源代码路径为/a/b/c/d.c
,GCOV_PREFIX_STRIP=2
,则实际使用的路径是c/d.c
,如果GCOV_PREFIX=/e/f
,则.gcda
实际存放的路径是/e/f/c/d.gcda
报告生成
针对某一个文件的执行情况,可以通过如下命令生成报告,并创建*.gcov
文件:
1 | $ gcov -a main.c |
常用选项,更多可参考Invoking gcov:
1 | -b:分支覆盖 |
注意事项
- 在编译时不要加优化选项,否则代码会发生变化,无法准确定位
- 代码中复杂的宏,比如宏展开后是循环或者其他控制结构,可以用内联函数来代替,因为
gcov
只统计宏调用出现的那一行 - 代码每一行最好只有一条语句
*.gcno
与*.gcda
需要匹配,两个文件是有时间戳来记录是不是匹配的- 若是编译动态库,需要在链接时
-lgcov
图形化展示
gcov
生成的报告分散在各个源码文件所对应的*.gcov
文件中,难以汇总分析,并且可视化效果较差,所以需要转化成可视图形化报告,有lcov
或gcovr
两个工具可以完成,两者功能基本相同,本文主要介绍gcovr
,是一个用Python
编写的开源软件,大小只有几十KB,安装参见官网
列表形式
代码覆盖率
1
2
3
4
5
6
7
8
9
10
11
12$ gcovr -r .
------------------------------------------------------------------------------
GCC Code Coverage Report
Directory: .
------------------------------------------------------------------------------
File Lines Exec Cover Missing
------------------------------------------------------------------------------
main.c 5 4 80% 15
say.c 3 3 100%
------------------------------------------------------------------------------
TOTAL 8 7 87%
------------------------------------------------------------------------------报告展示程序运行后覆盖了
80%
的代码分支覆盖率
1
2
3
4
5
6
7
8
9
10
11
12$ gcovr -b -r .
------------------------------------------------------------------------------
GCC Code Coverage Report
Directory: .
------------------------------------------------------------------------------
File Branches Taken Cover Missing
------------------------------------------------------------------------------
main.c 2 1 50% 14
say.c 0 0 --%
------------------------------------------------------------------------------
TOTAL 2 1 50%
------------------------------------------------------------------------------报告展示了在
main.c
中有一个分支没有执行到
XML文件形式
1 | $ gcovr --xml-pretty -r . |
HTML文件形式
1 | $ gcovr -r . --html -o xxx.html |
可以发现添加--html
参数后,可以生成html
文件,用浏览器打开,如下图:
还可以添加--html-details
选项,为每个代码文件单独生成html
1 | $ gcovr -r . --html --html-details -o xxx.html |
可以发现多了xxx.main.c.html
和xxx.say.c.html
,用浏览器打开xxx.html
,如下图:
文件名较之前带上了下划线,单击文件名,可以看到具体的代码覆盖情况,如下图:
其它
其它功能,如Filters
等,可以参考官方文档