准备环境:
qt-creator5.2.1 , gcov(gcc 默认安装),lcov(gcov 的图形化显示界面),qt_testlib
各环境介绍:
1.gcov
gcov
是一个可用于C/C++的代码覆盖工具,是gcc的内建工具。下面介绍一下如何利用gcov来收集代码覆盖信息。
想要用gcov收集代码覆盖信息,需要在gcc编译代码的时候加上这2个选项:
“-fprofile-arcs -ftest-coverage”,把这个简单的程序编译一下
gcc -fprofile-arcs -ftest-coverage hello.c -o hello
编译后会得到一个可执行文件hello和hello.gcno文件,当用gcc编译文件的时候,如果带有“-ftest-coverage”参数,就会生成这个.gcno文件,它包含了程序块和行号等信息
接下来可以运行这个hello的程序
./hello 5
./hello 12
运行结束以后会生成一个hello.gcda文件,如果一个可执行文件带有“-fprofile-arcs”参数编译出来,并且运行过至少一次,就会生成。
这个文件包含了程序基本块跳转的信息。接下来可以用gcov生成代码覆盖信息:
gcov hello.c 运行结束以后会生成2个文件hello.c.gcov和myfunc.c.gcov。打开看里面的信息:
-: 0:Source:myfunc.c
-: 0:Graph:hello.gcno
-: 0:Data:hello.gcda
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include
-: 2:
-: 3:void test(int count)
1: 4:{
-: 5: int i;
10: 6: for (i = 1; i < count; i++)
-: 7: {
9: 8: if (i % 3 == 0)
3: 9: printf (“%d is divisible by 3
n”, i);
9: 10: if (i % 11 == 0)
#
####: 11: printf (“%d is divisible by 11
n”, i);
9: 12: if (i % 13 == 0)
#####: 13: printf (“%d is divisible by 13
n”, i);
-: 14: }
1: 15:}
被标记为#####的代码行就是没有被执行过的,代码覆盖的信息是正确的.
1.2 使用gcov的3个阶段
(1) 编译
# gcc -f=profile-arcs -f test-coverage -o test test.c
# ls
test test.c test.gcno
-f profile-arcs -f test-coverage告诉编译器生成gcov需要的额外信息,并在目标文件中插入gcov需要的extra profiling information。因此,该命令在生成可执行文件test
的同时生成test.gcno文件(gcov note文件)。
(2) 收集信息
# ./test
Success
# ls
test test.c test.gcda test.gcno
执行该程序,生成test.gcda文件(gcov data文件)。
(3)
报告
# gcov test.c
File 'test.c'
Lines executed:87.50% of 8
test.c:creating 'test.c.gcov'
# ls
test test.c
test.c.gcov
test.gcda test.gcno
生成test.c.gcov文件,该文件记录了每行代码被执行的次数。
test.c.gcov
文件内容如下,蓝色表示笔者添加的注释。
-: 0:Source:test.c
-: 0:Graph:test.gcno
-: 0:Data:test.gcda
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include //前面的数字表明该clause被执行的次数,下同
-: 2:
-: 3:int main (void)
1: 4:{
-: 5: int i, total;
-: 6:
1: 7: total = 0;
-: 8:
11: 9: for (i = 0; i < 10; i++) //前面的数字11表明该clause被执行11次
10: 10: total += i;
-: 11:
1: 12: if (total != 45)
#####: 13: printf ("Failure/n");
-: 14: else
1: 15: printf ("Success/n");
1: 16: return 0;
-: 17:}
-: 18:
1.2 gcov的选项
gcov
的选项不多,也好理解,此处选3个典型的选项并结合例子加以说明。
(1) -a, --all-blocks
在.gcov文件中输出每个基本快(basic block)的执行次数。如果没有-a选项,则输出'main'函数这个block的执行次数,如上所示。使用该选项可以
Write individual execution counts for every basic block. Normally gcov outputs execution counts only for the main blocks of a line. With
this option you can determine if blocks within a single line are not being executed.
# gcov -a test.c File 'test.c'
Lines executed:87.50% of 8 //
代码覆盖率
test.c:creating 'test.c.gcov'
Test.c.gcov
文件内容。
-: 0:Source:test.c
-: 0:Graph:test.gcno
-: 0:Data:test.gcda
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include
-: 2:
-: 3:int main (void)
1: 4:{
-: 5: int i, total;
-: 6:
1: 7: total = 0;
-: 8:
11: 9: for (i = 0; i < 10; i++)
1: 9-block 0
10: 9-block 1
11: 9-block 2
10: 10: total += i;
-: 11:
1: 12: if (total != 45)
1: 12-block 0
#####: 13: printf ("Failure/n");
$$$$$: 13-block 0
-: 14: else
1: 15: printf ("Success/n");
1: 15-block 0
1: 16: return 0;
1: 16-block 0
-: 17:}
-: 18:
(2) -b, --branch-probabilities
在.gcov文件中输出每个分支的执行频率,并有分支统计信息。
# gcov -b test.c
File 'test.c'
Lines executed:87.50% of 8
Branches executed:100.00% of 4
Taken at least once:75.00% of 4
Calls executed:50.00% of 2
test.c:creating 'test.c.gcov'
-: 0:Source:test.c
-: 0:Graph:test.gcno
-: 0:Data:test.gcda
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include
-: 2:
-: 3:int main (void)
function main called 1 returned 100% blocks executed 86%
1: 4:{
-: 5: int i, total;
-: 6:
1: 7: total = 0;
-: 8:
11: 9: for (i = 0; i < 10; i++)
branch 0 taken 91%
branch 1 taken 9% (fallthrough)
10: 10: total += i;
-: 11:
1: 12: if (total != 45)
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
#####: 13: printf ("Failure/n");
call 0 never executed
-: 14: else
1: 15: printf ("Success/n");
call 0 returned 100%
1: 16: return 0;
-: 17:}
-: 18:
(3) -c, --branch-counts
在
.gcov
文件中输出每个分支的执行次数。
# gcov -c test.c
File 'test.c'
Lines executed:87.50% of 8
test.c:creating 'test.c.gcov'
-c是默认选项,其结果与"gcov test.c"执行结果相同。
2.lcov
lcov -d . -t ‘Hello test’ -o ‘hello_test.info’ -b . -c 指定lcov
在当前目录“.”去找代码覆盖的信息,输出为’hello_test.info’ ,这个hello_test.info是一个中间结果,需要把它用genhtml来处理一下,genhtml是lcov里面的一个工具。
genhtml -o result hello_test.info 指定输出目录是result。
一个完整的html报告就生成了,做一个连接,把这个目录连到随便一个web server的目录下,就可以看报告了。
3.总结:
gcov是配合gcc产生覆盖信息报告的工具;
lcov是将gcov产生的报告信息,以更直观的方式显示出来工具 基本的使用方法分为4个阶段:
(一)、gcc编译:产生插装后的目标文件test、gcov结点文件 test.gcno #gcc -fprofile-arcs -ftest-coverage -o test test.c # ls
test test.c test.gcno
说明:参数 fprofile-arcs 和 ftest-coverage 告诉gcc编译器:(1)在目标文件test 插装跟踪代码;(2)生成供gcov使用 test.gcno [gcov node 文件]。
因此,这里的生成的目标文件比正常编译的文件大。
(二)、运行目标文件:收集运行覆盖信息 test.gcda # ./test
Success -- 这里是运行结果。 # ls
test test.c test.gcno test.gcda 这里test.gcda运行结果,
(三)、gcov产生报告信息: test.c.gcov #gcov test.c File 'test.c'
Lines executed: 87.50% of 8 test.c: creating 'test.c.gcov' #ls
test test.c test.c.gcov test.gcda test.gcno
(四)、lcov:格式化test.c.gcov ,输出到 test.info文件 #lcov -d . -t 'test' -o 'test.info' -b . -c 说明:
-d . :参数 d指路径, "." 指当前路径 -t "name" :指目标文件,这里 是 test
-o "filename" :输出格式化后的信息文件名
(五)、genhtml:根据信息文件(.info)产生html 文档,输出到一个文件夹中
#genhtml -o result test.info
说明: -o directory :参数o (output)后面跟路径名称,在当前目录下创建指定目录,本例中是result
至此: 可以在result目录中打开index.html 浏览覆盖信息
一.创建测试用例
1.new project->other project ->Qt unit test 2.编写一个单元测试程序 文件列表:
qtestlib/tutorial1/testqstring.cpp qtestlib/tutorial1/tutorial1.pro
假设你要测试QString类的行为。首先,你需要一个用于包含测试函数的类。这个类必须从QObject继承:
class TestQString: public QObject {
Q_OBJECT private slots:
void toUpper(); };
注意你需要包含QTest头文件,并且测试函数必须声明为私有槽,这样测试框架才可以找到并执行他们。
然后你需要实现测试函数。实现看起来类似这样:
QVERIFY()宏将计算传入的表达式的值。如果为真,则测试函数继续进行;否则会向测试日志中增加一条描述错误的信息,并且该测试函数会停止执行。
但是如果需要向测试日志中增加更多的输出信息,你应该使用QCOMPARE()宏: void TestQString::toUpper() {
QString str = “Hello”;
QVERIFY(str.toUpper() == “HELLO”); }
如果两个字符串不相等,他们的值都会追加到测试日志中,这样失败的原因就一目了然了。
最后,为使我们的测试程序能够单独执行,需要加入下列两行: QTEST_MAIN(TestQString)
#include “testqstring.moc”
QTEST_MAIN()宏将扩展成一个简单的main()函数,该main()函数会执行所有的测试函数。注意:如果测试类的声明和实现都在同一个cpp文件中,需要包含产生的moc文件,以使Qt的内省机制起作用。 执行测试程序
运行生成的可执行文件,你会看到下列输出:
********* Start testing of TestQString ********* Config: Using QTest library 4.5.1, Qt 4.5.1 PASS : TestQString::initTestCase() PASS : TestQString::toUpper()
PASS : TestQString::cleanupTestCase() Totals: 3 passed, 0 failed, 0 skipped
********* Finished testing of TestQString *********
三.Mac 下具体配置
1.确保 gcol ,lcol,genhtml 已经安装 2.在工程文件pro中添加
QMAKE_CXXFLAGS += -g -Wall -fprofile-arcs -ftest-coverage -O0 QMAKE_LFLAGS += -g -Wall -fprofile-arcs -ftest-coverage -O0
LIBS += -lgcov
3. 创建processCoverage.sh #!/bin/bash
##############################################################################
# Copyright (c) 2013, Robert Wloch
# All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v1.0 # which accompanies this distribution, and is available at # http://www.eclipse.org/legal/epl-v10.html #
# Contributors:
# Robert Wloch - initial API and implementation
##############################################################################
if [ ! $# -eq 3 ]; then
echo "usage: ${0} <gcov-files-dir> "<file-pattern>" <target-dir>" exit 0 fi
lcov -d ${1} -c -o ${1}/coverage.info
lcov --list-full-path -e ${1}/coverage.info ${2} –o ${1}/coverage-stripped.info
genhtml -o ${3} ${1}/coverage-stripped.info
lcov -d ${1} –z
exit 0