本文主要结合gdb和gcov开源工具,在linux环境下进行白盒测试。
白盒测试的主要目的有两点,一点是验证软件需要是否在代码中被覆盖,二是进行代码覆盖率分析,尽可能多的覆盖所有软件代码。显然,最重要的第一点。分析代码覆盖率就是为了检查代码跟需求是否匹配,然后再继续根据需求添加新代码,或者删除掉根本没有执行的死代码。
所以当代码覆盖率达到100%,说明代码已经很完美的匹配了软件需求,白盒测试工作也就结束了。这就是白盒测试的根本目的。
下面就结合具体的例子说明linux白盒测试流程。
这里有个简单的 程序,计算1+2+3..+8的和 sum。如果有条程序需求,当sum不等于36,设置quit=0,否侧,设置quit=1。
$cat calnumber.c
1 #include <stdio.h> 2 3 int main() 4 { 5 int i,sum,number; 6 int quit; 7 number = 8; 8 sum = 0; 9 for(i = 0; i <= number; i++) 10 { 11 sum += i; 12 } 13 14 if(sum != 36) 15 { 16 quit = 0; 17 printf("sum = %d\n", sum); 18 } else 19 { 20 quit = 1; 21 printf("sum is 36\n"); 22 } 23 24 if(quit) printf("Finish!\n"); 25 26 return 0; 27 }
|
很显然需求设计两个用例,一个是sum=36, 另外一个是sum!=36,这样程序需求也就覆盖到了。目前,我们还没有看到程序,但是我们已经可以设计用例了,所以说在编码人员写程序之前,测试人员就可以结合程序需求设计所有的测试用例。当程序写完之后,测试人员就可以马上进行测试。
我们把这个用例写成gdb脚本。具体如下,需要熟悉gdb命令。
$cat calnumber.gdb
# For comments file calnumber # Test Case 1 echo \n echo ---------------------\n echo Test Case 1\n echo \n break calnumber.c:main run break calnumber.c:9 continue echo "check number == 8"\t print number == 8 echo "check sum == 0"\t print sum == 0 echo "set number = 4"\t print number = 4 break calnumber.c:14 continue echo "set sum = 10"\t print sum = 10 break calnumber.c:24 continue echo "check quit == 0"\t print quit == 0 echo "check i == 5"\t print i == 5 echo "check sum == 10"\t print sum == 10 Delete continue # Test Case 2 echo \n echo ---------------------\n echo Test Case 2\n echo \n break calnumber.c:main run break calnumber.c:24 continue echo "check i == 9"\t print i == 9 echo "check sum == 36"\t print sum == 36 echo "check quit == 1"\t print quit == 1 Delete continue # ------------------------------- quit |
如何结合gdb和gcov进行白盒测试?主要有两个阶段:
1.编译程序,执行gdb调试脚本。
在编译程序的时候加上-fprofile-arcs -ftest-coverage参数。所以这里运行
gcc -fprofile-arcs -ftest-coverage -g -o calnumber calnumber.c
gdb的命令参数-x可以从文件读出gdb调试命令再执行。运行
gdb -x calnumber.gdb > calnumber.res
下面是gdb脚本的输出:
$cat calnumber.res
GNU gdb 6.5.50.20060706-cvs (cygwin-special) Copyright (C) 2006 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i686-pc-cygwin". --------------------- Test Case 1 Breakpoint 1 at 0x401083: file calnumber.c, line 4. Breakpoint 1, main () at calnumber.c:4 4 { Breakpoint 2 at 0x401096: file calnumber.c, line 9. Breakpoint 2, main () at calnumber.c:9 9 for(i = 0; i <= number; i++) "check number == 8" $1 = 1 "check sum == 0" $2 = 1 "set number = 4" $3 = 4 Breakpoint 3 at 0x4010c2: file calnumber.c, line 14. Breakpoint 3, main () at calnumber.c:14 14 if(sum != 36) "set sum = 10" $4 = 10 Breakpoint 4 at 0x401121: file calnumber.c, line 24. Breakpoint 4, main () at calnumber.c:24 24 if(quit) printf("Finish!\n"); "check quit == 0" $5 = 1 "check i == 5" $6 = 1 "check sum == 10" $7 = 1 sum = 10 Program exited normally. --------------------- Test Case 2 Breakpoint 5 at 0x401083: file calnumber.c, line 4. Breakpoint 5, main () at calnumber.c:4 4 { Breakpoint 6 at 0x401121: file calnumber.c, line 24. Breakpoint 6, main () at calnumber.c:24 24 if(quit) printf("Finish!\n"); "check i == 9" $8 = 1 "check sum == 36" $9 = 1 "check quit == 1" $10 = 1 sum is 36 Program exited normally. |
现在分析下测试用例的成功率。这里用check作为搜索的关键字。这个关键字是在gdb脚本中自己定义的。
$grep -r "check" calnumber.res "check number == 8" $1 = 1 "check sum == 0" $2 = 1 "check quit == 0" $5 = 1 "check i == 5" $6 = 1 "check sum == 10" $7 = 1 "check i == 9" $8 = 1 "check sum == 36" $9 = 1 "check quit == 1" $10 = 1 $grep -r "check" calnumber.res | cut -f2 $1 = 1 $2 = 1 $5 = 1 $6 = 1 $7 = 1 $8 = 1 $9 = 1 $10 = 1 |
说明用例的10个比较均是正确的,成功率为100%。
2.用gcov得到代码覆盖率。
上一步结束后,在当前目前下会产生两个文件:calnumber.gcda和calnumber.gcno。 这里不关注它们。
直接执行gcov calnumber.c 得到
$gcov calnumber.c
File `calnumber.c'
Lines executed:100.00% of 14
calnumber.c:creating `calnumber.c.gcov'
说明覆盖率文件已经产生了,我们看下calnumber.c.gcov文件:
$cat calnumber.c.gcov
-: 0:Source:calnumber.c -: 0:Graph:calnumber.gcno -: 0:Data:calnumber.gcda -: 0:Runs:2 -: 0:Programs:1 -: 1:#include <stdio.h> -: 2: -: 3:int main() function main called 2 returned 100% blocks executed 100% 2: 4:{ 2: 5: int i,sum,number; 2: 6: int quit; 2: 7: number = 8; 2: 8: sum = 0; 16: 9: for(i = 0; i <= number; i++) -: 10: { 14: 11: sum += i; -: 12: } -: 13: 2: 14: if(sum != 36) -: 15: { 1: 16: quit = 0; 1: 17: printf("sum = %d\n", sum); -: 18: } else -: 19: { 1: 20: quit = 1; 1: 21: printf("sum is 36\n"); -: 22: } -: 23: 2: 24: if(quit) printf("Finish!\n"); -: 25: 2: 26: return 0; -: 27:} |
分析这个文件说明目前的代码覆盖率是100.00%。为了简化流程,写了个脚本完成上述任务。
$cat flow.sh
#!/bin/sh output_key_word='check' case_key_word='Case' usage() { echo "Usage : flow.sh file_name" exit; } # input file is $1.res # output file is $2.ver # generate_ver() { echo --------------------------------------- > $2 echo -e "\tTest Results Summary\n" >> $2 echo -e -n "Total Number of Comparisons\t\t:\t" >> $2 comparison_nums=`grep -r $output_key_word $1 | cut -f2 | wc -l` echo -e "$comparison_nums" >> $2 echo -e -n "Total Number of Comparisons Failed\t:\t" >> $2 failed_nums=`grep -r $output_key_word $1 | cut -f2 | grep -r '= 0'| wc -l` echo -e "$failed_nums" >> $2 echo -e -n "Total Number of Comparisons Passed\t:\t" >> $2 passed_nums=`expr $comparison_nums - $failed_nums` echo -e "$passed_nums" >> $2 echo -e -n "Total Number of Test Cases Included\t:\t" >> $2 case_nums=`grep -r $case_key_word $1 | wc -l` echo -e "$case_nums" >> $2 echo >> $2 echo -e -n "Percentage of Comparisons Passed\t:\t">>$2 percentage=`awk 'BEGIN{print '$passed_nums'/'$comparison_nums'}'` echo -e "$percentage" >> $2 echo >> $2 echo --------------------------------------- >> $2 } [ $# -ne 1 ] && usage # Clean rm -f *.gcno *.gcda *.c.gcov rm -f *.ver *.rpt *.res # Complier gcc -fprofile-arcs -ftest-coverage -g -o $1 $1.c # Debug [ -e $1.gdb ] && gdb -x $1.gdb > $1.res # Test Result Report generate_ver $1.res $1.ver [ -e $1.ver ] && echo "Generate VER file successfully!" # Code Coverage Report gcov $1.c > $1.rpt [ -e $1.c.gcov ] && cat $1.c.gcov >> $1.rpt [ -e $1.rpt ] && echo "Generate RPT file successfully!" |
如果把calnumber.gdb中第二个用例删掉,我们再来看看结果。
$./flow.sh calnumber Generate VER file successfully! Generate RPT file successfully! $cat calnumber.ver --------------------------------------- Test Results Summary Total Number of Comparisons : 5 Total Number of Comparisons Failed : 0 Total Number of Comparisons Passed : 5 Total Number of Test Cases Included : 1 Percentage of Comparisons Passed : 1 --------------------------------------- $cat calnumber.rpt File `calnumber.c' Lines executed:85.71% of 14 calnumber.c:creating `calnumber.c.gcov' -: 0:Source:calnumber.c -: 0:Graph:calnumber.gcno -: 0:Data:calnumber.gcda -: 0:Runs:1 -: 0:Programs:1 -: 1:#include <stdio.h> -: 2: -: 3:int main() function main called 1 returned 100% blocks executed 82% 1: 4:{ 1: 5: int i,sum,number; 1: 6: int quit; 1: 7: number = 8; 1: 8: sum = 0; 6: 9: for(i = 0; i <= number; i++) -: 10: { 5: 11: sum += i; -: 12: } -: 13: 1: 14: if(sum != 36) -: 15: { 1: 16: quit = 0; 1: 17: printf("sum = %d\n", sum); -: 18: } else -: 19: { #####: 20: quit = 1; #####: 21: printf("sum is 36\n"); -: 22: } -: 23: 1: 24: if(quit) printf("Finish!\n"); -: 25: 1: 26: return 0; -: 27:}
|
显然没有第二个用例,代码的20-21行就没有覆盖到,覆盖率只有85.71% 所以测试用例的多少和好坏直接影响程序的覆盖率。gcov的用法可以参见man,网上也有很多资料,我就不多说了。
以上就是linux白盒测试流程,希望对大家有帮忙。