代码覆盖率分析(gcov)(转)
上一篇 / 下一篇 2008-08-11 12:48:40 / 个人分类:SoftTest
我的栏目
- 栏目:
为什么需要代码覆盖率分析?
T[6D~[4J.a0
h*w^U;KK c
}#n1C*O0在发布代码的时候,我们常常会对其进行一系列的测试来协调软件的性能和功能,使他们和预计的相同。但是检验通常都是相当的困难,即使程序相当的简单。开发者常常会借助一些测试工具(test suite)来模拟或者重建执行脚本。如果测试程序组是彻底的,那么程序的各个功能都将被测试到并且都可以证明是可以工作的。
A!^0TZ:}HB051Testing软件测试网J r$W.I2M
但是怎样才算彻底呢?简单点说就是测试程序的每一条路径,验证每一个结果,执行每一条语句,证明没一句语句是没用的。gcov就是一个用来检验你的每一句语句是否都执行了的工具。51Testing软件测试网(H;]:n^!z+{"~4f{.]
51Testing软件测试网pz&I&R;Y8o/m4Em
什么是代码覆盖率分析?
MU
P_B
kp0代码覆盖率分析就是找到定位没用的或者不执行的代码的过程。没用的代码不会存在什么问题,但是他们会影响程序的可读性;不执行的代码则可能是未来bug的所在。所以找到他们,把他们从你的程序中移处是大有裨益的。
RY9D({UHBVn0覆盖率分析主要有下面的几个过程:51Testing软件测试网3^'}K"ap&E*V$n
通过测试程序组找到不执行的程序段;51Testing软件测试网FKs4o'?0J9P%k'_ s
添加额外测试程序组,以便增加代码覆盖率;
L
?NR G0 决定代码覆盖率的定量测度,他也是程序质量的间接测度。51Testing软件测试网C5O5P_s.v
代码覆盖率分析的缺陷51Testing软件测试网n~9}Jt)fF
`
代码覆盖率分析不能找出程序的逻辑错误。考虑一下下面的代码51Testing软件测试网"R Ls.a$}$X
10: rc = call_to_xx ();
sW#h|ANEU011: if (rc == ERROR_FATAL)51Testing软件测试网$K
E3KT%Tq
12: exit(2); /* exit with error code 2 */51Testing软件测试网_Ik/uZh'P![
13: else51Testing软件测试网Vkx1m#P*`[:Yc,l
14: /* continue on */
xCf(xHPr0当测试程序段运行到11行时,11行始终都不能为真。call_to_xx返回了另外的一个错误比如ERROR_HANDLE,除非我们加入这种错误的处理方式的代码。51Testing软件测试网5]m:IV,B-P#l]
代码覆盖测试工具不会告诉你什么是必须的,他们只能显示已经存在的代码的覆盖率。51Testing软件测试网`2Cojd#~J}
代码覆盖率的类型
l\2D
|Yw0gcov可以用来测量各种形式的代码覆盖率。最常见最有用的两种是分支覆盖(branch coverage)和循环覆盖(loop coverage)51Testing软件测试网y9`5v2Q;K]
分支覆盖证明各个方向的每一条分支都被执行到了。循环覆盖试图证明循环内部的每一条路径都被测试到了。循环覆盖似乎非常的复杂,但基本上只要满足下面的三个状况,就可以作了。
+Umq+vxKgS&J#d0 1。循环条件不满足,循环没有内部没有执行;
JzBg4kZ5i]3M.j
f0 2。循环条件就满足了一次,循环内部就执行了一次;51Testing软件测试网Sd7B7JKm
3。循环条件至少满足了两次,循环至少执行了两次。
1Z1^@JSZ3k4|0举个例子51Testing软件测试网g5a){!M#s-T)w a@7PF
void function(int number)51Testing软件测试网,a.\~N_z~ b.E
{51Testing软件测试网ac-j ~4f
if (number % 2) == 0)
9_3~t7|z\@8Z0 printf("even \n");
6c-]~4M:X.k-ox'R6@0 for (;number < 9; number++){51Testing软件测试网0|z[7M(c'sS!};`#j
printf("number is %d\n", number);51Testing软件测试网(CjTbZ+e}{I
a
}
2l Oql9kp4a,WU0}
F}3h?%J3p;H051Testing软件测试网i*uA0BY)G
function(11); 满足状况一51Testing软件测试网t%zp"{j3s~pg#rI
function(8); 满足状况二
.n'Jzr8T5J)q0function(6); 满足状况三
*YX'y(j)Do8{0
代码覆盖率工具gcov的使用
1?o/l\~P4z%P0要使用gcov,需要在我们用gcc编译程序时加入两个参数fprofile-arcs和ftest-coverage.
S-\ g)h\0fprofile-arcs参数使gcc创建一个程序的流图,之后找到适合图的生成树。只有不在生成树中的弧被操纵(instrumented):gcc添加了代码来清点这些弧执行的次数。当这段弧是一个块的唯一出口或入口时,操纵工具代码(instrumentation code)将会添加到块中,否则创建一个基础块来包含操纵工具代码。
V8?qFVJ
h8J'|"A0gcov主要使用.gcno和.gcda两个文件51Testing软件测试网~g|K(i1r
.gcno是由-ftest-coverage产生的,它包含了重建基本块图和相应的块的源码的行号的信息。51Testing软件测试网'Y1y{ XwJ9MDyKr
.gcda是由加了-fprofile-arcs编译参数的编译后的文件运行所产生的,它包含了弧跳变的次数和其他的概要信息。51Testing软件测试网;xS!_$^n9nz|j
51Testing软件测试网C'd$deoI^
下面是一个简要的范例:
N9S#w5u!t*i0 1 #include <stdlib.h>51Testing软件测试网4bio0w!f
b
2 #include <stdio.h>
5mJ4OwT0TZ SNv4_+{0 3
m6vs%b5Mg
J%S&qH1M0 4 int main(int argc,char** argv)51Testing软件测试网#EV3Cw/T%}'I
5 {51Testing软件测试网UpvU,|B \
6 int x,y;51Testing软件测试网U*^o2b0B/U]5NM
7 int arraysize;
-PWQc#f f#mVnG0 8 int **array;
Y,SdG9kf0 9
D(lr[1BTVUa
L0 10 if(argc!=2)
1B_A/^I_7Ut(x0 11 {51Testing软件测试网
^5C;b2W9JNF
12 printf("Usage: %s Enter arraysize value\n;",argv[0]);
qU9Pp5Gy/j `\0 13 exit(-1);
-T7h3ZkW,g`M0 14 }
0U!X8a)RD8O!R0 15 else
1{D6`/Uo{G$e0 16 {51Testing软件测试网k:Xf%C{+^2e
17 arraysize = atoi(argv[1]);51Testing软件测试网vk$a8z k+Oe
18 if(arraysize <=0)
w;KH~t0 19 {51Testing软件测试网bT"[\&i
20 printf("Array size must be larger than 0\n;");51Testing软件测试网j2X
A6h5j6];]0[M+x7l
21 exit(-1);51Testing软件测试网(p[B0n8F,GQX
\
22 }51Testing软件测试网Qpw;HC h
23 }51Testing软件测试网x-b[Dp
A\U
2451Testing软件测试网4a$Oo4DR@.r_
25 array = (int**) malloc( arraysize*sizeof(int*));51Testing软件测试网C#|_#D^
m,n
2651Testing软件测试网e x4n7mH
27 printf("Creating an %d by %d array \n",arraysize,arraysize);
7uwkr4RZ
SU0 28
5J'{/\7E9v&De] y;K0 29 if(array == NULL)51Testing软件测试网7t+`hh)r'x[
30 {51Testing软件测试网.nnztA'BO)q
31 printf("Malloc failed for array size %d \n",arraysize);51Testing软件测试网0y
?$M_M"u,hB
32 exit(-1);
5}$fxt+b~6M!{dJf0 33 }51Testing软件测试网So#@5l*K@
E'?
34
5AoRvz]2v0 35 for (x=0;x<arraysize;x++)
%lGy3s$C ` C7f+fw0 36 {
{[
oO_\,_5o8{0 37 array[x] = (int*) malloc (arraysize*sizeof(int));
-U7_r?qxca hD0 38
a_+IN_x
Ky0 39 if(array[x] == NULL)
,{o6S.P}2wz:g0 40 {
&b@2gJP-|0 41 printf("Failed malloc for array size %d\n",arraysize);
z6I,Ps%K0 42 exit(-1);
K(r%gVv2@%]0 43 }51Testing软件测试网.l?N,x+D$k
44 }51Testing软件测试网6I5N#u:v'a4jEZ:}
45
#j-l4Jp4T7rV
A"[h6t0 46 exit(0);
G(fZ"Q3p/C
Snw0 47 }51Testing软件测试网1Y
uY3dIFn8]
51Testing软件测试网#kY(I@E
@ta
$ gcc -fprofile-arcs -ftest-coverage -g -o sample test.c
_Dw$c{3|5}&wfn0$ ./sample 1051Testing软件测试网hFf,nS4]+d(C,O
Creating an 10 by 10 array51Testing软件测试网Qy7Oc U7B.\!B
$ gcov test.c51Testing软件测试网H!A0p_(e0q"I@/C
File ''/usr/include/sys/sysmacros.h''
8AB,|+Ukmn&h4B U2|P0Lines executed:0.00% of 6
x)tm)I:gD0/usr/include/sys/sysmacros.h:creating ''sysmacros.h.gcov''51Testing软件测试网3Z"zZiEf/[!u
Q6tt
x'VPHu\0File ''test.c''
5jF_6Dy*Gs6T_:a0Lines executed:57.89% of 1951Testing软件测试网 r]zQ.j
@
G
test.c:creating ''test.c.gcov''
RkA |A*Q8jB5Fwn0$ cat test.c.gcov51Testing软件测试网g?CR7tK|wb
-: 0:Source:test.c51Testing软件测试网s^#^ v$N+o
-: 0:Graph:test.gcno
"prQ3{F A6m ]]0 -: 0:Data:test.gcda
3C"{8YN2]M!Y
v0 -: 0:Runs:1
pon&\l$goe0 -: 0:Programs:151Testing软件测试网v/E)J:y3Nj L
-: 1:#include <stdlib.h>51Testing软件测试网Bh#b9Z6Y
-: 2:#include <stdio.h>
_'d5{GV)Ik0 -: 3:51Testing软件测试网*u!pg!q;xO
?]
-: 4:int main(int argc,char** argv)
:wA'}rJY$\/B7}!n7p0 1: 5:{
)V h6l+K,B6Ql0 -: 6: int x,y;51Testing软件测试网0Fd
uaj'HT
-: 7: int arraysize;
V|!}#CKpH0 -: 8: int **array;51Testing软件测试网]"@cv}k
-: 9:
a,H\#|Tf%\/p
X0 1: 10: if(argc!=2)51Testing软件测试网Z1b)B,B(bL#}
-: 11: {
K5]I:KNf0 #####: 12: printf("Usage: %s Enter arraysize value;\n",argv[0]);
g\!vXI/vN0 #####: 13: exit(-1);51Testing软件测试网3FTo%q?|%e2R`3E+~K#F
-: 14: }
aMNzG}n:E0 -: 15: else
ch#hEy8O5yij;k0 -: 16: {
Y%M+O
\?t0 1: 17: arraysize = atoi(argv[1]);51Testing软件测试网0wW)f'j:IHf1a
1: 18: if(arraysize <=0)
]e}m'?&C0 -: 19: {51Testing软件测试网2OSpL.Yg*^2y
#####: 20: printf("Array size must be larger than 0;\n");51Testing软件测试网9@g:aO#hJs
#####: 21: exit(-1);
+s!i({$v^9RT0 -: 22: }
t+u jL#UIH-W0 -: 23: }51Testing软件测试网5i5_IB
J}/^
-: 24:
Ux#^?e4S:Oe0 1: 25: array = (int**) malloc( arraysize*sizeof(int*));51Testing软件测试网dG
l)T8Nj:z
-: 26: