c/c++代码的unit-test中覆盖率的统计
gcov lcov genhtml工具
gcov伴随gcc 发布。gcc编译加入-fprofile-arcs -ftest-coverage 参数生成二进制程序,执行测试用例生成代码覆盖率信息。
使用这些工具产生代码覆盖率的统计,需要经过:编译参数设置&编译、运行、gcov生成覆盖信息、locv生成 html报表数据、genhtml根据报表数据生成可视化的html报告 这几个步骤
编译参数设置&编译
用GCC编译的时候加上-fprofile-arcs -ftest-coverage选项,链接的时候也加上。
fprofile-arcs参数使gcc创建一个程序的流图,之后找到适合图的生成树。只有不在生成树中的弧被操纵(instrumented):gcc添加了代码来清点这些弧执行的次数。当这段弧是一个块的唯一出口或入口时,操纵工具代码(instrumentation code)将会添加到块中,否则创建一个基础块来包含操纵工具代码。
编译成功后,会生成各*.c对应的 *.gcno文件。*.gcno是由-ftest-coverage产生的,它包含了重建基本块图和相应的块的源码的行号的信息。
运行
也就是执行单元测试进程,如果编译参数中加了gcov相关的参数后,执行结果会生成 各 *.c文件对应的 *.gcda文件。*gcda是由加了-fprofile-arcs编译参数的编译后的文件运行所产生的,它包含了弧跳变的次数和其他的概要信息(而gcda只能在程序运行完毕后才能产生的)。
gcov生成覆盖信息
Gcov执行函数覆盖、语句覆盖和分支覆盖。gcov工具会生成各*.c文件对应的 *.c.gcov 文件,不过*.c.gcov在lcov命令执行后,会被删除。*.c.gcov包含了函数和代码执行次数的信息。

locv生成 html报表数据
Lcov则是上的gcov 结果展现的一个前端,可以将覆盖率信息转换成html展现,它用来解析*.c.gcov中晦涩的字符,生成代码覆盖的信息,并输出到文件(*.info),genhtml根据*.info文件生成html报告。
lcov -d ./ -c -o $(LCOV_INFO) -b ./
genhtml根据报表数据生成可视化的html报告
genhtml -o $(COV_REPORT) $(LCOV_INFO) --show-details –legend
最终的报告,*.html文件

完整的makfile
# makefile for sample cpputest INC_DIR := -I../inc -I../inc/mysql -I../src/libcas
SRC_FILE := libcas.c cJSON.c qs_thread.c qs_init.c qs_paltask.c qs_cmd.c qs_db.c qs_main.c
SRC_OBJS := libcas.so
SRC_LNAME := cas TEST_GROUP_FILE := test.c mocks.c
TEST_EXE := test_libcas RUN_PREPARE := "cp ../bin/cas.json ." UT_LOG := result.log
CU_PROJECT_NAME := $(shell pwd |awk -F "/" '{print $$NF}' )
LCOV_INFO := $(CU_PROJECT_NAME).info
COV_REPORT := $(CU_PROJECT_NAME)_cover all: $(TEST_EXE) $(SRC_OBJS) CPPUTEST_HOME := /usr/cpputest CC := gcc -Wformat
CCFLAGS := -g -DLINUX $(INC_DIR) -shared -fPIC -fprofile-arcs -ftest-coverage --coverage
CCFLAGS += -D CPPUTEST # 编译测试文件时, 忽略被测代码 *.c 的main函数, test.c 的代码中用了宏CPPUTEST
CCLDFLAGS := -lgcov
CCLDFLAGS += -L../bin -lm -lvst_memory -lvst_shell_log -ldbase_comm -lbase_log -lvst_plat -lpthread \
-loam_proxy -ldbase_my CPP := g++
CPPFLAGS := -g -w -fpermissive -DLINUX -fprofile-arcs -ftest-coverage --coverage
CPPFLAGS += -I$(CPPUTEST_HOME)/include $(INC_DIR)
CPPLDFLAGS := -lgcov
CPPLDFLAGS += -Wl,-rpath,./,-rpath,./../bin -L$(CPPUTEST_HOME)/lib -L../bin -lCppUTest -lCppUTestExt
CPPLDFLAGS += -lssl -ldl -lpthread -lvst_com -lvst_memory -lvst_plat -lvst_encrypt\
-lvst_shell_cli -lvst_shell_log -lm -lvst_thpool -lreadline \
-lvst_thpool -ldbcfg_parse -ldata_parse \
-lipdr -laccpwd -lstat -luas -ldata_stat CPPLDFLAGS += -l$(SRC_LNAME) SRCDIR := $(shell ls -d ../src/*)
vpath
vpath %.c $(SRCDIR) $(SRC_OBJS): $(SRC_FILE)
$(CC) -o $@ $^ $(CCFLAGS) $(CCLDFLAGS) $(TEST_EXE): $(TEST_GROUP_FILE) $(SRC_OBJS)
$(CPP) -o $@ $^ $(CPPFLAGS) $(CPPLDFLAGS) .PHONY: clean
clean:
@echo "clean..."
rm -f $(SRC_OBJS) $(TEST_EXE)
rm -f *.gcda
rm -f *.gcno
rm -f *.gcov
rm -f $(UT_LOG)
rm -rf $(COV_REPORT)
rm -f *.info run:
eval $(RUN_PREPARE)
./$(TEST_EXE) &> $(UT_LOG) cover:
for file in $(SRC_FILE);\
do\
gcov -b "$$file";\
done
lcov -d ./ -c -o $(LCOV_INFO) -b ./
genhtml -o $(COV_REPORT) $(LCOV_INFO) --show-details --legend
一些问题
一开始的时候,生成的报告,只有 line和functions的统计,没有branches的统计。
在执行 make cover后,日志只有:

gcov命令执行的日志中,有branch的信息:

开始解决问题的思路:是不是gcov 或lcov的命令参数不对,查了命令及尝试了修改参数后,仍未解决。
后来发现 lcov的命令日志中有如下告警:

按告警信息搜索,发现了 stackoverflow上有个相似的问题:
http://stackoverflow.com/questions/13378640/lcov-can-not-collect-branch-coverage-statistics
参照上面的思路,修改了/etc/lcovrc中
lcov_branch_coverage=1
genhtml_branch_coverage=1
后,最终的html报告中才有branches的统计。
c/c++代码的unit-test中覆盖率的统计的更多相关文章
- Mysql基础代码(不断完善中)
Mysql基础代码,不断完善中~ /* 启动MySQL */ net start mysql /* 连接与断开服务器 */ mysql -h 地址 -P 端口 -u 用户名 -p 密码 /* 跳过权限 ...
- php示例代码之类似于C#中的String.Format方法
php示例代码之类似于C#中的String.Format方法 原文来自于 http://stackoverflow.com/questions/1241177/c-string-format-equ ...
- 利用Roslyn把C#代码编译到内存中并进行执行
Tugberk Ugurlu在其博文<Compiling C# Code Into Memory and Executing It with Roslyn>中给大家介绍了一种使用.NET下 ...
- ASP.net中网站访问量统计方法代码(在线人数,本月访问,本日访问,访问流量,累计访问)
一.建立一个数据表IPStat用于存放用户信息 我在IPStat表中存放的用户信息只包括登录用户的IP(IP_Address),IP来源(IP_Src)和登录时间 (IP_DateTime),些表的信 ...
- mac github工具将命令当下来的代码拖入macgithub中就可以
mac github工具将命令当下来的代码拖入macgithub中就可以,刚開始傻傻的就知道点击那个加入button,总是在当下来的文件夹下创建个文件夹.并且代码不能同步
- git使用方法----如何利用git管理代码?如何使用git将代码传到github中去
## 在文件夹中打开 git here; 1.git init ===初始化一个仓库(这个仓库会存放,git对我们代码进行备份的文件)2.配置个人信息 -- --在git中设置当前使用的用户是==( ...
- .NET/C# 异常处理:写一个空的 try 块代码,而把重要代码写到 finally 中
不知你是否见过 try { } finally { } 代码中,try 块留空,而只往 finally 中写代码的情况呢?这种写法有其特殊的目的. 本文就来说说这种不一样的写法. 你可以点开这个链接查 ...
- Google自动广告,将广告代码放置在 HTML 中的什么位置?
Google自动广告,将广告代码放置在 HTML 中的什么位置? 为自动广告生成广告代码后,您需要将此代码放置在要展示广告的每个网页中.您应将广告代码放置在网页的 <head> 标记(或正 ...
- Java用代码演示String类中的以下方法的用法
用代码演示String类中的以下方法的用法 (1)boolean isEmpty(): 判断字符串是不是空串,如果是空的就返回true (2)char charAt(int index): 返回索引上 ...
随机推荐
- selenium===selenium自动化添加日志(转)
本文转自 selenium自动化添加日志 于logging日志的介绍,主要有两大功能,一个是控制台的输出,一个是保存到本地文件 先封装logging模块,保存到common文件夹命名为logger.p ...
- 微软推出ASP.NET Core 2.0,并支持更新Visual Studio 2017
微软推出ASP.NET Core 2.0的一般可用性,并发布.NET Core 2.0.该公司还推出了其旗舰集成开发环境(IDE)的更新:Visual Studio 2017版本15.3和Visual ...
- mybatis 联结查询
一.查询 员工(tbl_employee)时,关联 查询出 员工对于的部门信息 (tab1_dept),一对一查询,或者多对一查询 适用 emp bean里面 包含 部门bean dept属性对象 1 ...
- C#面向对象(OOP)入门—第二天—多态和继承(继承)
介绍: 第一天的内容主要是不同情形下的方法重载.这一部分则主要讲面向对象中继承的概念.首先用一个要点图形来定义继承. 继承 一个简单的例子: ClassA: class ClassA:ClassB { ...
- HDU 4768: Flyer
题意: 有N个社团,每个社团三个属性A,B,C,表示会向编号A+k*C的同学发传单(k=0,1,2... && A+k*C <= B).题目保证最多有一个人收到的传单数是奇数. ...
- 如何生成[0,maxval]范围内m个随机整数的无重复的有序序列
在这里我们将待生成的数据结构称为IntSet,接口定义如下: class IntSetImp { public: IntSetImp(int maxelements,int maxval); void ...
- hdu 1041(递推,大数)
Computer Transformation Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/ ...
- JS框架的实现
众多流行的JS库都不同程度的污染了原生JS,最典型的如Prototype ,Mootools .JQuery则完全例外,一个匿名函数执行后便诞生了集所有API为一身的强大 $ .虽然如此,JQuery ...
- (翻译)Xamarin.Essentials: 移动应用的跨平台 API
原文地址:https://blog.xamarin.com/xamarin-essentials-cross-platform-apis-mobile-apps/ 当使用 Xamarin 开发 IOS ...
- IO扩展控件(System.IO.Abstractions)
刚看到这个Namespace的时候还以为是.Net Framework里自带的包,结果查了一圈无任何结果.果断上Github搜索,一击即中 https://github.com/tathamoddie ...