• QT unit test code coverage


       

    准备环境:

    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

  • 相关阅读:
    groovy集合
    groovy函数、字符串、循环
    groovy运行程序和类型推断
    常见IT英语短语一
    常见IT英语单词
    认识Groovy
    maven入门
    springboot之内嵌tomcat修改端口号
    springboot手动配置数据源:
    img与父元素的间隙解决
  • 原文地址:https://www.cnblogs.com/lvdongjie/p/4153024.html
Copyright © 2020-2023  润新知