c语言程序的测试
C 语言程序的测试
程序调试的任务是排除程序中的错误,使程序能顺利地运行并得到预期的效果。程序的调试阶段不仅要发现和消除语法上的错误,还要发现和消除逻辑错误和运行错误。除了可以利用编译时提示的“出错信息”来发现和改正语法错误外,还可以通过程序的测试来发现逻辑错误和运行错误。 程序的测试任务是尽力寻找程序中可能存在的错误。在测试时要设想到程序运行时的各种情况,测试在各种情况下的运行结果是否正确。 有时程序在某些情况下能正确运行,而在另外一些情况下不能正常运行或得不到正确的结果,因此,一个程序即使通过编译并正常运行而且可以得到正确的结果,还不能认为程序就一定没有问题了。要考虑是否在任何情况下都能正常运行并且得到正确的结果。测试的任务就是要找出那些不能正常运行的情况和原因。下面通过一个例子来说明。
求一元二次方程ax 2+bx+c=0的根。 有人根据求根公式:x 1,2=-b ±*b -4ac
a
,编写出以下程序:
#include #include Void main() {
float a,b,c,disc.x1,x 2;
scanf(“%f,%f,%f”,&a,&b,&c);
disc=b*b-4*a*c;
x 1=(-b+sqrt(disc))/(2*a); x 2=(-b -sqrt(disc))/(2*a);
printf("x 1=%6.2f,x 2=%6.2f\n"x 1, x 2); Return 0; }
当输入a,b,c 的值为1,-2,-15时,输出x 1的值为5,x 2的值为-3. 结果是正确无误的。但若是输入a,b,c 的值为3,2,4时,屏幕上出现“出错信息”,
2
程序停止运行,原因是对负数求平方根了(b -4ac=4-48=-44
因此,此程序只适用于b 2-4ac ≧0的情况。不能说上面的程序是错的,而只能说程序“考虑不周”,不是在任何情况下都是正确的。使用这个程序必须满足一定的前提(b 2-4ac ≧0),这样,就给使用程序的人带来不便。在输入数据前,必须先算一下,b 2-4ac 是否大于或等于0. 应要求一个程序能适应各种不同的情况,并且都能正常运行并得到相应的结果。
下面分析一下求方程ax 2+bx+c=0的根,有几种情况: (1)a ≠0时:
①b 2-4ac>0,方程有两个不等的实根:x 1,2=-b ±b *b -4ac ②b 2-4ac=0,方程有两个相等的实根:x 1=x2=-2a ;
a
;
2
i 4ac -b -③b -4ac
a
(2)a=0时,方程就变成一元一次的线性方程:bx+c=0. ①当b ≠0时,x=-c/b;
②当b=0时,方程变为:0x+c=0. 〃当c=0时,x 可以为任何值; 〃当c ≠0时,x 无解。 综合起来,共有6种情况: ①a ≠0,b 2-4ac>0; ②a ≠0,b 2-4ac=0; ③a ≠0,b 2-4ac
⑤a=0,b=0,c=0; ⑥a=0,b=0,c ≠0。
应当分别测试程序在以上6种情况下的运行情况,观察它们是否符合要求。为此,应准备6组数据。用这6组数据去测试程序的“健壮性”。在使用上面这个程序时,显然只有满足①②情况的数据才能使程序正确运行,而输入③~⑥情况的数据时,程序出错。这说明程序不“健壮”。为此,应当修改程序,使之能适应以上6种情况。可将程序改为: #include #include Void main() {
float a,b,c,disc.x1,x 2, p,q; printf(“input a,b,c:”); scanf(“%f,%f,%f”,&a,&b,&c); if(a==0) if(b==0) if(c==0)
printf(“It is trivial.\n”) ; else
printf(“It is impossbile.\n”) ; else
printf(“It has one solution:\n”); printf(“x=%6.2f\n”, -c/b); else {
disc=b*b-4*a*c; if(disc>=0) if(disc>0) {
printf(“It has two real solutions:\n”) x1=(-b+sqrt(disc))/(2*a); x2=(-b -sqrt(disc))/(2*a);
2
printf("x 1=%6.2f,x 2=%6.2f\n"x 1, x 2); } else {
printf(“It has two same real solutions:\n”);
printf(“x 1=x2=%6.2f\n”, -b/(2*a)); }
else {
printf(“It has two complex solutions:\n”); p=-b/(2*a);
q=sqrt(-disc)/(2*a);
printf(“x 1=%6.2f+%6.2fi,x 2=%6.2f -%6.2fi\n”,p,q,p,q); } } }
为了测试程序的“健壮性”,我们准备了6组数据:
①3,4,1;②1,2,1;③4,2,1;④0,3,4;⑤0,0,0;⑥0,0,5 分别用这6组数据作为输入的a 、b 、c 的值,得到以下的运行结果: ①input a,b,c:3,4,1 It has two real solutions: x 1=-0.33,x 2=-1.00 ②input a,b,c:1,2,1
It has two same real solutions: x 1=x2=-1.00
③input a,b,c:4,2,1
It has two complex solutions: x 1=-0.25+0.43i,2=-0.25-0.43i ④input a,b,c:0,3,4 It has one solution: X=-1.33
⑤input a,b,c:0,0,0 It is trivial.
⑥input a,b,c:0,0,5 It is impossbile. 经过测试,可以看到程序对任何输入的数据都能正常运行并得到正确的结果。 以上是根据数学知识知道输入数据有6种方案。但在有些情况下,并没有现成的数学公式作依据,例如一个商品管理程序,要求对各种不同的检索作出相应的反应。如果程序包含多条路径(如由if 语句形成的分支),则应当设计多组测试数据,使程序中每一条路径都有机会执行,观察其运行是否正常。
测试的关键是正确地准备测试数据。如果只准备4组测试数据,程序都能正常运行,仍然不能认为此程序已无问题。只有将程序运行时所有可能的情况都做
过测试,才能作出判断。
测试的目的是检查程序有无“漏洞”。对于一个简单的程序,要找出其运行时全部可能执行到的路径,并正确地准备数据并不困难。但是如果需要测试一个复杂的大程序,要找到全部可能的路径并准备出所需的测试数据并非易事。例如,有两个非嵌套的if 语句,每个if 语句有两个分支,它们所形成的路径数目为2x2=4。如果一个程序包含100个非嵌套的if 语句,每个if 语句有两个分支则可能的路径数目为2100≈1.267651x1030。实际上进行测试的只是其中一部分(执行几率最高的部分)。因此,经过测试的程序一般来说还不能轻易宣布“没有问题”,只能说:“经过测试的部分无问题”。正如检查身体一样,经过内科、外科、眼科、五官科等各科例行检查后,不能宣布被检查者“没有任何病症”一样,他可能有隐蔽的、不易查出的病症。所以医院的诊断书一般写:“未发现异常”,而不能写“此人身体无任何问题”。 读者应当了解测试的目的,学会组织测试数据,并根据测试的结果完善程序。 应当说,写完一个程序只能说完成任务的一半(甚至不到一半)。调试程序往往比写程序更难,更需要精力、时间和经验。常常有这样的情况:写程序用一天就完成了,而调试程序两三天也未能完成。有时一个小小的程序会出错五六处,而发现和排除一个错误,有时竟需要半天,甚至更多。希望读者通过实践掌握调试程序的方法和技术。