为了保证软件的质量和可靠性,人们力求在分析、设计等各个开发阶段结束之前,对软件进行严格的技术评审。
软件测试是为了发现错误而执行程序的过程。
或者说
软件测试是根据软件开发各阶段的规格说明和程序的内部结构而精心设计一批测试用例(即输入数据及其预期的输出结果),并利用这些测试用例去运行程序,以发现程序错误的过程。
目的:以最少的时间和人力,系统的找出软件中潜在的各种错误和缺陷。
Grenford J. Myers 就软件测试目的提出以下观点:
测试不能表明软件中不存在的错误,它只能说明软件中存在的错误。
任何工程产品都可以使用以下两种方法之一进行测试:
前者是黑盒测试,后者是白盒测试。
黑盒测试方法主要是为了发现:是否有不正确或遗漏了的功能?输入能否正确地接受?能否输出正确的结果?是否有数据结构错误或外部信息(例如数据文件)访问错误?性能上是否能够满足需求?是否有初始化或终止性错误?
所以,用黑盒测试发现程序中的错误,必须在所有可能的满足输入条件和输出条件中确定测试数据,检查程序是否都能产生正确的输出。
白盒测试主要是对程序模块进行检查:对程序模块的所有独立的执行路径至少测试一次;对所有的逻辑判定,取“真”与取“假”的两种情况都至少测试一次;在循环的边界和运行界限内执行循环体;测试内部数据结构的有效性等等。
因此白盒测试又称为结构测试或逻辑驱动测试。
在测试阶段,穷举测试不可行,必须精心设计测试用例,从数量极大的可用测试用例中精心地挑选少量的测试数据,使得采用这些测试数据能够达到最佳的测试效果,或者说它们能够高效率地把隐藏的错误尽可能多的揭露出来。
事实说明,软件测试有一个致命的缺陷,即测试的不完全、不彻底性。由于任何程序只能进行少量(相对于穷举的巨大数量而言)的有限的测试,所以在发现错误时能说明程序有问题,但在未发现错误时,不能说明程序中没有错误、没有问题。
逻辑覆盖是以程序内部的逻辑结构为基础的设计测试用例的技术,它属于白盒测试。
逻辑覆盖可分为:语句覆盖、判定覆盖、条件覆盖、判定-条件覆盖、条件组合覆盖、路径覆盖。
以下将分别做出扼要的介绍。在所介绍的几种逻辑覆盖中,均以下图所示的程序为例。其中有两个判断,每个判断都包含符合条件的逻辑表达式,并且,符号“∧”表示“AND”运算,“∨”表示“OR”运算。a、b、c、d、e 分别为不同的路径。
若把各条路径应满足的逻辑表达式综合起来,可以进行如下推导,其中使用叹号“! ”表示“非”运算。
L1(a->c->e)
= { (A>1) and (B=0) } and { (A=2) or (X/A>1) }
= (A>1) and (B=0) and (A=2) or (A>1) and (B=0) and (X/A>1)
= (A=2) and (B=0) or (A>1) and (B=0) and (X/A>1)
L2(a->b->d)
= !{ (A>1) and (B=0) } and !{ (A=2) or (X>1) }
= { !(A>1) or !(B=0) } and { !(A=2) and !(X>1) }
= !(A>1 ) and !(A=2 ) and !(X>1 ) or !(B=0) and !(A=2) and !(X>1)
= (A≦1) and (X≦1) or (B≠0) and (A≠2) and (X≦1)
L3(a->b->e)
= !{ (A>1) and (B=0)} and { (A=2) or (X>1) }
= { !(A>1) or !(B=0) } and { (A=2) or (X>1) }
= !(A>1) and (X>1) or !(B=0) and (A=2) or !(B=0) and (X>1)
= (A≦1) and (X>1) or (B≠0) and (A=2) or (B≠0) and (X>1)
L4(a->c->d)
= { (A>1) and (B=0) } and !{ (A=2) or (X/A>1) }
= (A>1) and (B=0) and (A≠2) and (X/A≦1)
语句覆盖就是设计若干个测试用例,运行被测程序,使得每一个可执行语句至少执行一次。
如图例中的的程序,正好所有的可执行语句都在路径L1上,所以选择路径L1设计测试用例,就可以覆盖所有的可执行语句。
测试用例的设计格式如下:
【输入的(A,B,X),输出的(A,B,X)】
为图例设计的满足语句覆盖的测试用例是:
【(2,0,4),(2,0,3)】覆盖 ace【l1】
从程序中每个可执行语句都得到执行这一点来看,语句覆盖的方法似乎能够比较全面地检验每一个可执行语句。但与其它覆盖相比,语句覆盖是最弱的逻辑覆盖准则。
判定覆盖就是设计若干个测试用例,运行被测试程序,使得程序中每个判断的取真分支和取假分支至少经历一次。判定覆盖又称为分支覆盖。
例如图例中的例子,如果选择路径L1和L2,可得满足要求的测试用例:
【(2,0,4),(2,0,3)】覆盖 ace【L1】
【(1,1,1),(1,1,1)】覆盖 abd【L2】
如果选择路径L3和L4,还可得另一组可用的测试用例:
【(2,1,1),(2,1,2)】覆盖 abe【L3】
【(3,0,3),(3,1,1)】覆盖 acd【L4】
所以,测试用例的取法不唯一。注意有例外情形,例如,若把图例中例子的第二个判断条件 X>1 错写成 X<1,那么利用上面两组测试用例,仍能得到同样结果。这表明,只是判定覆盖,还不能保证一定能查出在判断条件中存在的错误。因此,还需要更强的逻辑覆盖准则校验判断内部条件。
以上仅讨论了两出口的判断,我们还应该把判定覆盖准则扩充到多出口判断(如case语句)的情况。
条件覆盖就是设计若干个测试用例,运行被测程序,使得程序中每个判断的每个条件的可能取值至少执行一次。
如图例中,我们可以事先对所有条件的取值加以标记。例如:
对于第一个判断:
则可选取测试用例如下:
测试用例 | 通过路径 | 条件取值 | 覆盖分支 |
---|---|---|---|
【(2,0,4),(2,0,3)】 | ace(L1) | T1,T2,T3,T4 | c,e |
【(1,0,1),(1,0,1)】 | abd(L2) | !T1,T2,!T3,T4 | b,d |
【(2,1,1),(2,1,2)】 | abe(L3) | T1,!T2,T3,!T4 | b,e |
或
测试用例 | 通过路径 | 条件取值 | 覆盖分支 |
---|---|---|---|
【(1,0,3),(1,0,4)】 | abe(L3) | !T1,T2,!T3,T4 | b,e |
【(2,1,1),(2,1,2)】 | abe(L3) | T1,!T2,T3,!T4 | b,e |
注意,前一组测试用例不但覆盖了所有判断的取真分支和取假分支,而且覆盖了判断中所有条件的可能取值。但是最后一组测试用例虽满足了条件覆盖,却只覆盖了第一个判断的取假分支和第二个判断的取真分支,不满足判定覆盖的要求。
判定-条件覆盖就是设计足够的测试用例,使得判断中每个条件的所有可能取值至少执行一次,同时每个判断本身的所有可能判断结果至少执行一次。
例如,对于图例中的个判断,若 T1,T2,T3,T4 及 !T1,!T2,!T3,!T4 的含义如之前所属,则只需要设计以下两个测试便可覆盖图例的8个条件取值以及4个判断分支。
测试用例 | 通过路径 | 条件取值 | 覆盖分支 |
---|---|---|---|
【(2,0,4),(2,0,3)】 | ace(L1) | T1,T2,T3,T4 | c,e |
【(1,1,1),(1,1,1)】 | abd(L2) | !T1,!T2,!T3,!T4 | b,d |
判断-条件覆盖也有缺陷。从表面上看,它测试了所有条件的取值,但是事实并非如此。因为往往某些条件掩盖了另一些条件。
为彻底地检查所有条件的取值,可以将图例中的多重条件判定分解,形成如下图所示的由多个基本判断组成的流程图。这样可以有效地检查所有的条件是否正确。
所谓条件组合覆盖就是设计足够的测试用例,运行被测程序,使得每个判断的所有可能的条件取值组合至少被执行一次。
不可能用所有可以输入的数据来测试程序,而只能从全部可供输入的数据中选择一个子集进行测试。如何选择适当的子集,以便尽可能多的发现错误。解决方法之一就是等价类划分。
等价类是指某个输入域的子集合,在该子集合中,各个输入数据对于揭露程序中的错误都是等效的。
并合理的假设:测试某个等价类的代表值等价于对于这一类其他值的测试。
因此,可以把全部可供输入的数据合理划分为若干等价类,在每一个等价类中取一个数据作为测试的输入,这样就可以用少量代表性测试数据,达到测试的要求。
等价类的划分有两种不同的情况:
在设计测试用例时,要同时考虑有效等价类和无效等价类。软件不能都只接受合理的数据,还要经受意外的考验,检验出无效的或不合理的数据,这样的软件测试才是全面性的。
以下结合具体实例给出几条划分等价类的原则:
在确定了等价类后,建立等价类表,列出所有划分出的等价类:
输入数据 | 有效等价类 | 无效等价类 |
---|---|---|
…… | …… | …… |
再从划分出的等价类中按以下原则选择测试用例:
上述原则中,原则2完全是为了把测试工作量减到最小,原则3则尽可能的把多个错误分开。
在某程序设计语言的语法中规定:“标识符是以字母开头,后面跟字母或数字的任意组合而构成的。有效字符数为8个,最大字符数80个。”并且规定:“标识符必须先说明,再使用。”“在同一说明语句中,标识符至少必须有一个”
依次,建立输入等价类表如下(表中括号中的数字为等价类编号):
输入数据 | 有效等价类 | 无效等价类 |
---|---|---|
标识符个数 | 1个(1),多个(2) | 0个(3) |
标识符字符数 | 1~80个(4) | 0个(5),>80个(6) |
标识符组成 | 字母(7),数字(8) | 非字母数字字符(9),保留字(10) |
第一个字符 | 字母(11) | 非字母(12) |
标识符使用 | 先说明后使用(13) | 未说明已使用(14) |
边界值分析是对等价类划分方法的补充。
通常输入等价类与输出等价类的边界是需要认真考虑的。应该选取正好等于、刚刚大于或刚刚小于边界的值作为测试数据,而不是选取等价类中的典型值或任意值作为测试数据。
复习《软件工程概览》第10章的软件测试方法,记录摘要,总结。
2019-10-18