Skip to content
Table of contents

软件测试

4 min read ··· views #软件测试 / #gcov

单元测试

Gcov 是一个测试覆盖程序,集成在 GCC 中,随 GCC 一起发布。

基本概念

基本块 BB

基本块指一段顺序执行的程序代码:当其中第一条语句被执行后,块内每一条语句都会被执行一次,因此基本块内所有语句的执行次数相同。基本块一般由多个顺序执行的语句后接一个跳转语句组成。

跳转 ARC

从一个 BB 到另一个 BB 的跳转称为一个 ARC。要知道程序中每个语句和分支的执行次数,就必须知道每个 BBARC 的执行次数。

程序流图

如果把 BB 作为一个节点,一个函数中的所有 BB 就构成一个有向图。根据图论可知,有向图中 BB 的入度和出度相同,因此只要知道部分 BBARC 的执行次数,就可以推断出全部。这里选择由 ARC 的执行次数来推断 BB 的执行次数,所以只需对部分 ARC 插桩,只要能统计出所有 BBARC 的执行次数即可。

原理

测试程序首先进行编译预处理,生成汇编文件,并完成插桩。插桩时会在源文件末尾插入一个静态数组,数组的大小等于该源文件中桩点的个数,数组的值就是各桩点的执行次数;每个桩点插入 3~4 条汇编语句,直接写入生成的 *.s 文件。汇编文件经汇编生成目标文件,程序运行过程中由桩点负责收集执行信息。

使用

编译

测试代码 say.c 如下:

#include <stdio.h>

int say(char *what) {
    printf("------ %s\n", what);
    return 0;
}
c

main.c 如下:

#include <stdio.h>

extern int say(const char *);

int main(int argc, const char *argv[]) {

 if (argv[1]) {
	 say("hello");
 } else {
	 say("bye");
 }
 return 0;
}
c

添加 -fprofile-arcs -ftest-coverage -fPIC 编译参数编译程序,生成可执行程序和 *.gcno 文件,其中记录了行信息和程序流图信息:

$ gcc -fprofile-arcs -ftest-coverage -fPIC -O0 say.c main.c

$ ls
a.out  main.c  main.gcno  say.c  say.gcno
sh

数据收集

运行可执行文件,会在相应 *.o 文件所在目录默认生成 *.gcda 文件,其中记录了 *.c 文件中的程序执行情况,包括跳变次数等:

$ ./a.out
------ bye

$ ls
a.out  main.c  main.gcda  main.gcno  say.c  say.gcda  say.gcno
sh

报告生成

针对某个文件的执行情况,可以通过如下命令生成报告,并创建 *.gcov 文件:

$ gcov -a main.c
File 'main.c'
Lines executed:80.00% of 5
Creating 'main.c.gcov'
sh

常用选项如下,更多内容可参考 Invoking gcov

-b:分支覆盖
-a:所有基本块覆盖
-f:函数覆盖
plaintext

注意事项

  1. 编译时不要添加优化选项,否则代码会发生变化,无法准确定位。
  2. 代码中复杂的宏(如宏展开后是循环或其他控制结构)可以用内联函数代替,因为 gcov 只统计宏调用出现的那一行。
  3. 每行代码最好只包含一条语句。
  4. *.gcno*.gcda 需要匹配,两个文件通过时间戳记录是否匹配。
  5. 若编译动态库,链接时需要添加 -lgcov

图形化展示

gcov 生成的报告分散在各个源码文件对应的 *.gcov 文件中,难以汇总分析,可视化效果也较差,因此需要转换成可视化的图形报告。lcovgcovr 两个工具可以完成这项工作,两者功能基本相同。其中 gcovr 是一个用 Python 编写的开源软件,大小只有几十 KB。

列表形式

  1. 代码覆盖率
$ 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%
------------------------------------------------------------------------------
sh

报告显示程序运行后覆盖了 80% 的代码。

  1. 分支覆盖率
$ 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%
------------------------------------------------------------------------------
sh

报告显示 main.c 中有一个分支没有执行到。

HTML 文件形式

$ gcovr -r . --html -o xxx.html
$ ls
a.out  main.c  main.gcda  main.gcno  say.c  say.gcda  say.gcno  xxx.html
sh

添加 --html 参数后即可生成 html 文件,用浏览器打开,如下图所示: gcovr_xxx.png

还可以添加 --html-details 选项,为每个代码文件单独生成 html 文件:

$ gcovr -r . --html --html-details -o xxx.html
$ ls
a.out  main.c  main.gcda  main.gcno  say.c  say.gcda  say.gcno  xxx.html  xxx.main.c.html  xxx.say.c.html
sh

可以看到多了 xxx.main.c.htmlxxx.say.c.html 两个文件,用浏览器打开 xxx.html,如下图所示: gcovr_xxx_detail.png

文件名较之前带上了下划线,单击文件名即可查看具体的代码覆盖情况,如下图所示: gcovr_xxx_main.png|612

测试样例生成

当前主流的商用代码测试软件大都支持测试样例自动生成。这里调研了老牌的测试软件 Parasoft C/C++ test 与国产新推出的测试工具 wings。

对比方面wingsC/C++ test
测试样例生成灵活性可以根据需求,修改赋值次数基于Google Test框架,一次性生成固定组值
测试类型见下方表格见下方表格
生成方式基于xml的值填充基于Google Test框架的测试样例代码
应用范围国产替代,使用较少市场占比极大
获取难易使用依赖于厂家的数据库格式,需要厂家提供转换插件,获取难度大有破解版,可用

image-20250222144740738|221