第 6章 系统测试、实施与维护
6.1 软 件 测 试
6.2 调 试
6.3 系 统 实 施
6.4 系 统 维 护
6.5 实 验 五
6.1 软 件 测 试
6.1.1 测试的基本概念软件测试是对软件计划,软件设计,软件编码进行查错和纠错的活动 。 测试的目的是为了找出软件开发过程中各个阶段的错误,以便分析错误的性质和确定错误的位置,并纠正错误 。
软件测试伴随着程序设计的出现而出现,随着软件技术的发展,人们对软件测试的认识也在不断加深 。 通常人们认为,软件测试是为了证明软件是正确的,。 实际上这种认识是错误的 。 1983年,IEEE提出的软件工程标准术语中软件测试的定义是:,使用人工或自动手段来运行或测定某个系统的过程,其目的在于检验它是否满足规定的需求,或弄清预期结果与实际结果之间的差别,。 G.J.Myers则认为,程序测试是为了发现错误而执行程序的过程,。
上面的两种定义有不同的强调方面,关于软件测试的概念,我们要注意以下两点:
(1) 软件测试是为了发现程序中的错误而不是证明程序的正确性 。
按照 Myers的观点,,成功的测试是发现了至今尚未发现的错误的测试,。 当然测试的目的不仅仅是发现错误,还包含检验,评价等 。
(2) 软件测试方法不仅仅是执行程序,也包括人工方法。事实上,
人工测试在某些测试阶段可以发现大部分的错误。
6.1.2 测试的基本原则要高质量地完成测试工作,找出软件中的错误,应该遵守下面的一些基本原则:
(1) 测试队伍与开发队伍应分别建立 。
开发和测试工作两者在思想和方法上都是不一样的,为了保证测试的质量,应分别建立开发和测试队伍。开发工作是建设性的,而在测试阶段,人们设计出一系列的输入数据(称为测试用例),目的是为了
“破坏”已经建造好的软件。就像给硬件产品做高低温试验、震动试验、
破坏性试验一样。而且一般程序编写者往往认为自己编写的程序是正确的,要他们找出自己程序中的错误是十分困难的。
(2) 设计测试用例时,要给出测试的预期结果 。
一个测试用例应由两部分组成:
① 对程序进行测试的一组输入数据的描述;
② 由这一组输入数据所产生的程序的预期输出结果的描述 。
预期输出结果不一定是精确的输出结果,对于一些复杂的计算,
人工计算结果可能需要很大的工作量,可以给出一个对输出结果有效范围的描述 。
(3) 设计测试用例时,应包括对有效的和期望的输入条件的测试,
也应包括对无效的和非期望的输入条件的测试 。
一个程序不仅当输入合法时能正确运行,而且当有非法输入时,
应该能够拒绝这些非法输入,并给出适当的提示信息。
(4) 在程序修改之后,要进行回归测试 。
对程序的任何修改都有可能引入新的错误,所以必须进行回归测试,即将以前的所有测试用例再次输入测试,而不是仅仅测试以前结果不正确的测试用例 。 回归测试有助于发现由于修改程序而引入的新错误 。
(5) 对发现错误较多的程序段,应进行深入的测试 。
如果发现某个程序段错误较多,则表明这个程序段质量很低,有可能隐藏有更多的错误,应该进行深入的测试。
6.1.3 测试方法软件测试方法有多种,这些测试方法具有不同的思路和出发点 。 总的来说,测试方法可分为静态测试方法和动态测试方法两大类 。
所谓静态测试方法,是指不在计算机上运行被测试程序,
而是采用其它手段达到对程序进行检测目的的测试方法 。 静态测试方法包括人工测试方法和计算机辅助静态分析方法 。
所谓动态测试方法,是指在计算机上运行被测试程序,
并用所设计的测试用例对程序进行检测的方法 。 动态测试方法根据设计测试用例的思想不同可分为白盒测试,黑盒测试以及穷举测试等 。
1,人工测试方法人工测试方法是指依靠人而不是计算机来对程序进行检测的方法 。
人工测试可以找出计算机测试不容易发现的错误,可以减少系统测试的总工作量 。 根据统计,人工测试能有效地发现 30%~70%的逻辑设计和编码错误 。
人工测试可以采用人工运行和代码审查的方式 。 代码审查可以由程序编写者本人非正式地进行,也可以由审查小组正式进行 。 代码审查主要是对照常见程序错误清单对程序代码进行分析审查,并将发现的错误记录下来 。
表 6.1是由 Myers提供的常见程序错误清单,该表主要针对
FORTRAN一类的程序设计语言所编写的程序,其它的程序设计语言编写的程序也可参照该清单。表中的参数相当于 C语言中函数的形式参数,而变元相当于 C语言中函数调用时的实际参数。
表 6.1 Myers提供的常见程序错误清单一、模块接口检查表
1.模块接收的输入参数个数与模块的变元个数是否一致?
2.参数与变元的属性是否匹配?
3.参数与变元所用的单位是否一致?
4.传送给被调用模块的变元的数目是否等于那个模块的参数的数目?
5.传送给被调用模块的变元属性和参数的属性是否一致?
6.传送给被调用模块的变元的单位和参数的单位是否一致?
7.传送给内部函数的变元属性,数目和次序是否正确?
8.是否修改了只是作为输入用的变元?
9.全程变量的定义在各个模块中是否一致?
10.有没有把常数当作变量来传送?
二、完成外部输入 /输出时的检查表
4,文件属性是否正确?
2.打开文件语句是否正确?
3.格式说明与输入 /输出语句给出的信息是否一致?
4.缓冲区大小与记录大小是否匹配?
5.是否所有文件在使用前都已打开了?
6.对文件结束条件的判断和处理是否正确?
7.对输入 /输出错误的处理是否正确?
8.输出信息中有没有正文错误?
三、模块局部数据结构的检查表
4,有没有不正确或不一致的说明?
2,有没有不正确的初始化和缺省值?
3,有没有错误的变量名?
4,有没有不相容的数据类型?
5,有没有下溢,上溢或地址错误?
四、计算错误检查表
4,对运算优先次序的错误理解或错误处理 。
2.发生了混合运算 ( 运算对象的类型不相容 ) 。
3.初始化错误 。
4.计算精度不够 。
5.表达式的符号表示错误 。
五、比较错误的检查表
4,不同数据类型的数据进行比较 。
2.逻辑运算符或其优先次序用错 。
3.本应相等的数据,由于精度原因而不相等 。
4.变量本身有错或比较有错 。
5.循环终止不正确或循环不止 。
6.“差 1”错 ( 多一次或少一次循环 ) 。
7.当遇到发散的迭代不能摆脱出来 。
8.循环控制变量修改有错 。
六、出错处理的检查表
1.对错误的描述难以理解 。
2.指明的错误并非实际遇到的错误 。
3.出错后尚未进行错误处理,错误条件已引起了系统干预 。
4.对错误的处理不正确 。
5.提供的错误信息不足,以致无法找到出错的原因 。
人工测试还可以采用软件审查的方式,它可以用于系统开发的各个阶段,对产品的质量进行评审。限于篇幅,本书不再详细介绍。
2,计算机辅助静态分析方法计算机辅助静态分析方法是利用计算机测试工具对被测程序的特性进行分析方法的总称 。
静态分析工具主要有下面几种形式:
(1) 静态确认工具:对程序进行静态分析和确认,收集一些程序中的信息,以查找程序中的各种缺陷和可疑的程序构造 。 例如,使用了一个尚未赋值的变量,或者赋了值的变量一直没有使用等 。
(2) 符号执行工具:以符号值作为程序的输入,使程序符号执行,对程序的运算规律加以检验 。
(3) 程序验证工具:交互式程序验证系统是证明程序正确性的一种工具 。 它通过系统内部基于符号的逻辑变换和结构归纳,提取程序的语义和结构的要点来分析证明程序的正确性 。
3,黑盒测试黑盒测试又称功能测试,即不管程序内部是如何编制的,只考虑程序输入和输出之间的关系,或只考虑程序的功能 。 因此,测试者必须根据软件的规格说明书来确定和设计测试用例 。 黑盒测试也被称为数据驱动测试或基于规格说明书的测试 。
黑盒测试适合于对内部结构未知的软件进行测试,例如对于外购的软件包,只能根据软件包的功能说明书进行测试 。 另外,用户对系统的验收测试也使用黑盒测试方法,因为用户关心的是软件是否能实现所需的功能 。 也可以说,黑盒测试是从用户观点进行的测试 。
4,白盒测试白盒测试也称为结构测试,它是根据被测试程序的逻辑结构设计测试用例。使用白盒测试方法需要了解程序的内部结构,对程序的不同逻辑路径进行测试。由于采用不同方法设计测试用例对程序的逻辑路径覆盖的程度不一,白盒测试又被称为基于“覆盖”的测试。覆盖率越高,
测试越充分。
5,穷举测试软件测试的主要目的是查找软件中存在的错误,而不能证明软件的正确性 。 实际上采用一般的测试方法根本无法证明软件的正确性 。 有人主张通过白盒或黑盒测试方法对所有可能的情况进行测试,如果所有的情况都是正确的,则可证明程序是正确的 。 这种方法被称为穷举测试,
实际上除了一些简单的程序外,它是无法实现的 。
使用黑盒测试进行穷举测试,必须穷举所有可能的输入数据 。 举一个简单的例子,假设输入三个无符号整数作为三角形的三条边长,判断该三角形是否为直角三角形 。 C语言中无符号整数的范围为 0~216-1,如果要穷举所有的输入数据,则测试用例数为 216*216*216≈3*1014,假定程序每执行一次需要 1 ms,则需要一万年 。
白盒测试要实现穷举测试同样难以实现,当程序中包含有较复杂的循环和条件语句嵌套时,可能的执行路径数目同样很多,测试用例要覆盖所有的执行路径是根本不可能的。
6.1.4 设计测试用例使用白盒测试和黑盒测试都需要设计测试用例,上一节中已经提到要将所有可能的情况穷举出来是不可能的,因此在设计测试用例时必须依据一定的原则,以保证既能对程序进行充分的测试,而测试用例的数目又不能太大 。 本节将介绍常用的白盒和黑盒测试用例设计的方法 。
1,白盒测试白盒测试根据模块设计阶段对模块内部逻辑结构的描述设计测试用例。根据测试用例对模块所有可能执行路径的覆盖程度,可将其分为语句覆盖、判定覆盖、条件覆盖、判定条件覆盖、条件组合覆盖和路径覆盖。
1) 语句覆盖语句覆盖要求所设计的用例使程序中的每一条语句至少执行一次 。
这是覆盖程度很低的一种覆盖标准 。 下面是一个简单的例子 。
假设程序的流程图如图 6.1所示,对应的 C语言源程序片段如下:
X=0;
if(A>1||B>2)
X=A+B;
printf(,%d”,X);
现在按语句覆盖标准设计测试用例,
只需设计一组测试用例使条件
,A>1 or B>2”成立即可,例如:
输入数据,A=2,B=0;
输出数据,X=2。
A > 1 o r B > 2
X = A + B
输出 X
X = 0
图 6.1 被测试程序的流程图这组测试用例虽然覆盖了所有的语句,但对条件语句的分支测试不充分,只测试了条件为真的分支。
如果条件表达式中的第一个条件表达式 A>1误写为
A=1( C语言中该表达式值为真),这组测试用例无法检测该错误。同样,如果条件表达式中的第二个条件表达式 B>2写错,这组测试用例也不能检测出程序的错误。
2) 判定覆盖判定覆盖要求对程序中所有判定的分支都必须能够执行到 。 对于上面的例子,可设计两组测试用例:
第一组输入数据,A=2,B=0; 输出数据,X=2;
第二组输入数据,A=1,B=0; 输出数据,X=0。
这两组测试用例分别使条件语句中的条件表达式取,真,和,假,,
很显然也是语句覆盖,但对程序的测试比语句覆盖更充分 。
判定覆盖也是一种较弱的覆盖,这里的例子对条件表达式中 B>2
的测试很不充分,没有测试该表达式为真的情况。
3) 条件覆盖条件覆盖是指设计的测试用例能使程序中判定的每一个条件的可能取值都满足一次 。
对于上面的例子,判定中有两个条件,每个条件的可能取值为:
条件 1,A>1 真 记为 T1
假 ( A≤1) 记为 F1
条件 2,B>2 真 记为 T2
假 ( B≤2) 记为 F2
可以设计两组测试用例:
第一组输入数据,A=2,B=3; 输出数据,X=2;满足 T1,T2;
第二组输入数据,A=1,B=0; 输出数据,X=0;满足 F1,F2。
在大部分情况下,条件覆盖比判定覆盖强,因为它使判定表达式中每个条件都取得了可能的值,而判定覆盖只关心整个判定的取值 。 读者可以很容易地看出,这里的两组测试用例也满足判定覆盖的要求 。
但条件覆盖并不一定总是满足判定覆盖的要求,对上面的例子,我们看下面的两组测试用例:
第一组输入数据,A=2,B=0; 输出数据,X=2;满足 T1,F2;
第二组输入数据,A=1,B=3; 输出数据,X=4;满足 F1,T2。
这两组测试用例虽然满足条件覆盖的要求,但它不满足判定覆盖的要求。
4) 判定 /条件覆盖判定 /条件覆盖是指设计足够的测试用例,使其既满足条件覆盖的要求又满足判定覆盖的要求 。 要求判定中每一个条件所有的取值都能满足一次,而且保证判定的每个分支都能执行到一次 。 很显然,判定 /条件覆盖比前面的几种覆盖标准更强 。
判定 /条件覆盖仍然有一定的不足,表面看起来它测试了所有条件的所有可能取值,但实际上往往有某些条件掩盖了另一些条件。假设判定由两个条件构成,例如,x and y”。如果 x取值为“假”,不管此时 y的取值为“真”还是为“假”,整个判定的值均为“假”。
5) 条件组合覆盖条件组合覆盖是指设计足够的测试用例,使得判定中各种条件可能的取值组合都能满足一次 。
对上面例子中的程序,判定中共有两个条件表达式,每个条件都有两种取值,因此共有四种取值组合,它们是:
① A>1,B>2;
② A>1,B≤2;
③ A≤1,B>2;
④ A≤1,B≤2。
请读者自行设计四组输入数据分别满足不同的取值组合,本书不再赘述 。
很显然,条件组合覆盖的测试用例必定满足判定 /条件覆盖,条件覆盖和判定覆盖的要求 。
6) 路径覆盖路径覆盖是指设计足够的测试用例,使其覆盖程序中所有可能的路径 。
前面在介绍穷举测试时,
我们提到对于一些含有复杂条件和循环嵌套的程序,其可能路径的数目很大,路径覆盖是无法实现的。对于一些简单的程序,路径覆盖还是可以实现的,我们看图 6.2所示的程序流程示意图。
s
a
b
c d
e
图 6.2 被测程序的流程图该流程图中共有两个判定,程序执行的所有可能的路径共有 4种:
sace,sade,sbce和 sbde。
对于一些含有循环及条件嵌套的程序,由于其可能的执行路径数目巨大,要实行真正的路径覆盖是不可能的。对于这样一些程序,
可以采取一些方法来简化测试用例的设计,例如通常可以将循环简化为进入循环和不进入循环的分支操作,则执行路径的数目将大大减少。
2,黑盒测试黑盒测试是根据功能说明书进行的测试,测试者只知道程序的输入和输出之间的关系或程序的功能 。 测试者必须仔细地研究程序的功能说明,找出程序的功能信息或输入和输出之间的关系,然后设计测试用例并推断测试结果的正确性 。 常用的黑盒测试方法有等价类划分,
边界值分析等 。
1) 等价类划分等价类划分是黑盒测试常用的一种方法 。 它的基本思想是:将所有可能的输入情况划分为若干个等价类,然后为每一个等价类设计一个测试用例,如果这个测试用例程序的输出结果是正确的,则认为对该类的所有数据该程序都能得到正确的输出结果 。
等价类划分方法测试的质量取决于等价类划分是否合理,这往往依赖于测试人员的经验。下面是等价类划分经常采用的一些规则:
(1) 如果规定了输入值的范围或值的个数,则取一个有效等价类,两个无效等价类 。 例如功能说明书规定,项数为 1~10”,则取一个有效等价类,项数在 1~10之间,,两个无效等价类,项数 <1”和,项数 >10”。
(2) 如果输入项规定了值的集合,则取一个有效等价类和一个无效等价类 。 例如规定电话号码,以数字开头,,则取一个有效等价类,以数字开头,,一个无效等价类,以字母或其它字符开头,。
(3) 如果规定了输入数据的一组值,而且程序对不同输入值进行不同处理,则每个允许的输入值分别是一个有效等价类,此外还有一个无效等价类。
(4) 如果规定了输入数据的规则,则取符合规则的一个有效等价类和若干不符合规则的无效等价类 。
(5) 如果规定了输入数据是整形,则可以划分出负整数,零,正整数三个等价类 。
以上只是一些可供参考的规则,实际工作中应仔细分析程序输入数据的要求,划分出有代表性的有效等价类和无效等价类 。
在确定输入数据的等价类时,常常还需要分析输出数据的等价类,
以便根据输出数据等价类导出输入数据的等价类。例如,输入三角形的三条边长,判断三角形是普通三角形、等腰三角形还是等边三角形,
在设计等价类时显然应根据输出结果进行等价类的划分。
在划分有效等价类之后,按照等价类设计测试用例时应该注意:
(1) 设计一个测试用例,使其覆盖尽可能多的尚未覆盖的有效等价类 。
(2) 设计一个测试用例,使其只覆盖一个无效等价类 。
之所以如此要求,是因为经验表明,程序员往往更注意有效输入,
而忽视对无效输入数据的处理 。
现在来看一个简单的例子 。 假设程序要求输入某城市的电话号码,
电话号码由三个部分构成 。 这三个部分的名称与内容分别是:
地区码:空白或三位数字;
前缀:非 ‘ 0’或 ‘ 1’开头的三位数字;
后缀:四位数字 。
假定被测试的程序接收符合上述规则的所有号码,拒绝所有不符合规则的号码 。 现在使用等价类划分法来对其进行测试 。
第一步,划分等价类 。 划分的等价类以表格形式 ( 表 6.2) 给出,并给每个等价类一个唯一的编号 。
输入条件 有效等价类 无效等价类地区码 空白⑴,3位数字⑵ 有非数字字符⑸,少于 3位数字⑹,多于 3位数字⑺
前 缀 从 200到 999之间的数字⑶
有非数字字符⑻,起始位为‘ 0’
⑼,起始位为‘ 1’⑽,少于 3位数字⑾,多于 3位数字⑿
后 缀 4位数字⑷ 有非数字字符⒀,少于 4位数字⒁,多于 4位数字⒂
表 6.2 电话号码的等价类划分第二步,确定测试用例 。 表中有四个有效等价类,可使用下面两个测试用例:
测试数据 测试范围 期望结果
( ) 276-2345 等价类 ⑴⑶⑷ 有效
( 635) 805-9321 等价类 ⑵⑶⑷ 有效对于 11个无效等价类,应选择 11个测试用例 。 限于篇幅,这里不再一一给出 。
2) 边界值分析法在等价类划分法中,代表一个等价类的测试数据可以在这个类的允许值范围内任意选择 。 假设输入数据 x的有效范围为 [1.0,10.0],则设计测试用例时,有效等价类的输入数据可为 1~ 10之间的任意数据,
例如 2.0。 如果程序员将 x>=1.0错写为 x>1.0,则所选定的测试用例将不能检测到这类错误 。 如果选择有效范围的边界上的测试用例,则对这类错误的测试效果将很好,这就是边界值分析的基本思想 。
各种资料和经验也表明,程序员在程序设计过程中往往对输入输出数据有效范围的边界不够重视,在处理边界情况时,程序最容易发生错误 。 使用边界值分析方法设计测试用例,暴露程序错误的可能性将更大 。
在对边界值进行分析,进行测试用例设计时,可参考下面的一些规则:
(1) 如果输入条件规定了取值范围,则应对该范围的边界内附近,恰好在边界上和边界外附近设计测试用例 。
例如,规定输入值的有效范围为 [1.0,10.0],则应对 0.9,1.0,1.1,9.9、
10.0,10.1设计测试用例 。
(2) 如果输入条件规定了数据的个数,则应对最小个数,最大个数,比最小个数少 1,比最大个数多 1等情况设计测试用例 。
(3) 对软件规格说明中的每一个输出条件仿照前面对输入条件使用的
( 1),( 2) 原则设计测试用例 。
边界值分析法通常不作为一种独立的测试方法,而是作为其它测试方法的一种补充 。 例如,使用等价类划分法设计测试用例后,再使用边界值分析法补充部分测试用例对边界情况进行测试 。
黑盒测试方法除了上面介绍的两种之外,常见的还有因果图,错误推测法和判定表驱动测试等 。 本书在此不进行详细介绍 。
6.1.5 测试过程与步骤软件测试的过程如图 6.3所示。
软件测试构造测试测试结果预期结果评价 纠错错误错误率数据可靠性模型可靠性预测修正的软件图 6.3 软件测试的过程图 6.3中的输入有两类,即:
(1) 软件,即待测试的软件,包括设计阶段相关的文档和源程序清单等 。
(2) 测试构造,包括测试计划,测试用例及预期的测试结果 。
将得到的测试结果与预期结果比较,如果不符,则意味着错误,需要纠正,经过纠错后的软件需要再进行回归测试,如此反复地进行;
如果相符,则根据测试过程中错误发生的情况建立可靠性模型,作为系统付诸实施后的维护工作的依据 。 这一点正如前面所讲的,测试的目的并不是证明软件的正确性,测试通过的软件仍然可能含有错误 。
大型软件的测试工作一般分为模块测试、集成测试、确认测试和系统测试四个阶段。下面我们对每个阶段的主要内容和方法进行简单的介绍。
6.1.6 模块测试程序模块是构成信息系统中软件部分的基本单位,模块的测试是信息系统软件测试的第一步 。 模块测试又叫单元测试,经验表明模块测试发现的错误占错误总数的 65%,其重要性显而易见 。 一个模块具有以下属性:
① 名字;
② 应完成的功能;
③ 实现功能所应采用的算法;
④ 内部使用的数据结构;
⑤ 模块接口 。
一个模块可被其它模块调用,因此要接收输入参数,并在该模块执行完成后给调用模块返回输出参数。该模块在执行过程中也可能调用其它模块,因此需要输出数据作为被调用模块的输入参数,并接收被调用模块返回的输入数据。
1,模块测试的内容模块测试针对模块的各项属性进行检验测试,主要内容有:
1) 模块接口测试在测试模块的其它属性之前,首先应对穿过模块接口的数据进行测试 。
如果数据不能正确地在模块之间传递,其它的动态测试将不能正常进行 。
在对模块接口进行测试和检验时,应着重参照 Myers提供的常见程序错误清单中的“模块接口检查表”和“完成外部输入 /输出时的检查表”来逐项检查。
2) 局部数据结构对于一个模块来说,局部数据结构通常是错误的发源地,应该设计相应的测试用例,以便发现下列类型的错误:
① 不一致或不正确的说明;
② 错误的初始化或错误的缺省值;
③ 不相容的数据类型;
④ 上溢,下溢和地址异常 。
除了局部数据结构外,如有可能,在模块测试期间也应检查全局数据对模块的影响 。
3) 覆盖条件和路径测试在单元测试期间,必须对重要模块的基本路径进行测试 。 应设计测试用例,用来发现由于不正确的计算,比较或不适当的控制流而造成的错误 。
计算中常见的错误有:
① 算术运算优先次序不正确或误解了运算次序;
② 运算方式不正确;
③ 初始化不正确;
④ 精度不够;
⑤ 表达式的符号表示不正确 。
程序中的比较运算和控制流向关系密切,通常在比较之后发生控制流的变化。测试用例应发现下述错误:
① 不同数据类型的数据进行比较;
② 逻辑运算符不正确或优先次序不正确;
③ 因为精度问题造成期待相等的数据不相等;
④ 循环终止条件不正确;
⑤ 不正确地修改循环变量。
4) 错误处理良好的程序设计应能预先估计到运算中可能发生的错误和异常,例如误操作或不正确的输入数据,并给出相应的处理措施 。 在模块测试时,
应有意地进行不合理输入,检查程序的错误处理能力 。 主要注意检查如下几种情况:
① 输出的出错信息难以理解;
② 输出的出错信息与实际不符;
③ 错误处理不正确;
④ 在错误处理之前,错误已引起系统干预 。 操作系统一般都具有一定的错误捕获能力,但是它给出的错误信息一般比较笼统,应用程序应在操作系统捕获错误之前,对错误进行处理 。
5) 边界测试对输入输出数据的各种等价类边界,以及分支条件和循环条件的边界,
都应测试模块能否正确工作 。
2,模块测试的步骤与方法单元测试常被当作编码的附属步骤,当编码完成后,程序员首先进行初步检查,然后可由专门的测试人员或采用码审查会的形式来进行测试 。
在确认没有语法错误之后,可针对每个模块单独地进行测试工作 。
模块的动态测试采取白盒测试的方法,根据模块设计阶段得到的模块的逻辑结构设计测试用例 。
由于模块不是完整独立的程序,往往不能独立地运行,在整个系统中既可能被别的模块调用,也可能调用其它的模块 。 要进行动态测试,必须要模拟这两类关系以建立一个独立的测试环境 。 在单元测试过程中,
需要设计两类辅助测试模块来模拟这两类关系 。 用以模拟被测模块的上级调用模块称为驱动模块;模拟被测模块运行过程中所调用的模块称为桩模块 。
驱动模块的作用是:在单元测试中从外部接受测试数据;把测试数据转发给被测模块,运行被测模块;接受被测模块的测试结果数据;输出结果数据 。 驱动模块一般包含三种语句:输入语句,仿照其上级模块调用格式的调用语句,输出语句 。
桩模块用来代替被测模块所调用的模块 。 一般只需打印接口数据并返回,以便于检测被测模块与其下级模块之间的接口,有时也需要用最简单的方法来模拟它所替代的模块的动作 。
驱动模块和桩模块只是为测试而编写的,一般都很简单,测试工作结束后它们就没有用处了 。
模块测试阶段如果发现程序有错,错误一般发生在编码和模块设计阶段,应对编码和模块设计阶段的工作进行检查,改正错误后重新测试,
直至模块能完成规定的功能 。
6.1.7 集成测试模块测试完成后,每个模块能正常完成规定的工作 。 进一步的工作就是将所有模块组装起来构成一个完整的系统 。
1,集成测试的基本方法实践表明,单个模块能正常工作,并不能保证组装后也能正常工作 。
常见的原因有:
① 模块间的接口未经过严格测试,可能存在错误;
② 一个模块可能会破坏另一个模块的功能;
③ 把子功能组合起来不能产生预期的主功能;
④ 单个模块可以接受的误差在组装后累计放大,超出可接受的程度 。
鉴于以上的原因,在模块的组装过程中必须进行测试,称为集成测试或组装测试。集成测试的主要目的是发现与接口有关的错误。
如果集成测试阶段发现错误,则可能是在总体设计阶段设计软件结构时模块之间接口定义有误 。
集成测试主要有非渐增式测试和渐增式测试两种方法 。
(1) 非渐增式测试的过程是:先对每个模块进行测试,再将所有模块按系统软件结构组装,然后进行测试 。 一般用黑盒测试法设计测试用例 。
(2) 渐增式测试的过程是:逐个将未经测试的模块组装到已经测试过的模块上,然后进行集成测试 。 它不严格区分模块测试和集成测试阶段 。
每加入一个新模块都进行一次测试,重复此过程直到系统组装完成 。
渐增式测试模块组装的顺序可分为自顶向下结合和自底向上结合两种方法。
1) 自顶向下结合自顶向下结合的方法是:按照软件结构图自顶向下进行结合,首先测试顶层模块,然后逐步加入下层模块。可采取先广度后深度逐层安装,
或者先深度后广度进行模块结合。自顶向下结合方法不需要编写驱动模块,因为模块被组装进来时,它的上层模块已安装好。
A
B C D
E F G
图 6.4所示的软件结构图采用先广度后深度逐层安装时,模块的安装顺序为 A→B→C→D→E→F→G ;
若采用先深度后广度结合方法,模块的安装顺序则为
A→B→E→C→F→D→G 。
图 6.4 软件结构图
2) 自底向上结合自底向上结合的方法是:按照软件结构图自底向上,逐步安装与测试,直到测试结束。图 6.4的软件结构测试过程如图 6.5所示,分三步组装测试(图中 di表示驱动模块)。自底向上的结合方式只需要驱动模块,不需要桩模块。
d1 d2 d3
E F G B C D
E F G
d4 d5 d6
B C D
E F G
A
图 6.5 自底向上结合
2,不同测试方法的比较非渐增式测试方法单元测试阶段使用的辅助模块较多,适合于较小规模的系统 。 而且如果系统规模很大,测试中若发现错误,错误的定位将非常困难 。
渐增式测试逐步组装系统,很容易发现错误发生在哪个模块,适合于大规模的系统 。
采用自顶向下结合可在程序测试的早期实现并验证系统的主要功能,
及早发现上层的接口错误,但对底层关键模块中的错误发现较晚 。 采用自顶向下结合不能多个测试小组同时工作,测试周期较长 。
采用自底向上测试的优缺点与自顶向下相反,可以及早发现底层关键模块中的错误,但到测试的后期才能看到系统的全貌 。 采用自底向上结合可以多个测试小组同时展开工作,测试不同的子系统 。
在实际测试工作中可以采取混合的测试策略,自底向上和自顶向下测试同时展开,对系统的上层采用自顶向下的组装方法,而对系统的中,
下层模块采用自底向上组装测试的方法 。
6.1.8 确认测试确认测试,也称为验收测试 。 在集成测试之后,软件已组装完成,
接口错误也已改正,下一步应该验证软件的有效性,由用户参与测试,
检验软件功能是否与用户的要求一致 。
确认测试通过黑盒测试法来证实软件的功能与用户要求是否一致 。
测试计划和测试过程的目标是:检查功能,性能要求是否达到,文档资料是否正确完整以及其它要求如可移植性,错误恢复能力和易维护性等是否满足 。
确认测试如果发现功能或性能与用户要求有差距,通常与需求分析阶段的差错有关 。 因涉及面较广,通常需要与用户协商来妥善解决 。
对于一些通用的软件,要求所有客户进行验收确认是不可能的 。 这类软件确认测试一般分为两个阶段,称为
Alpha( α) 测试和 Beta( β) 测试 。 Alpha测试在开发者的场所由用户在开发者关注和控制的环境下进行 。 Beta测试则是在一个或多个客户自己的场所由最终用户进行,开发者不到场 。 客户记录下测试中遇到的所有问题,试运行一个阶段后把这些问题报告给开发者 。
6.1.9 系统测试软件经过确认测试后,最终还要与系统中的其它部分配套运行 。 系统测试的任务就是测试软件与系统其它部分是否能正常配套工作 。 系统测试通常有以下几类测试:
(1) 恢复测试:
(2) 安全测试:
(3) 强度测试:
(4) 性能测试:
6.1.10 测试阶段的主要文档测试阶段的主要文档包括测试计划和测试分析报告 。
单元测试作为编码阶段的附带步骤,一般没有独立的文档,这里讲的测试主要是指整个程序系统的组装测试和确认测试 。
1,测试计划测试计划包括对每项测试活动的内容、进度安排、
设计考虑、测试数据的整理方法及评价准则。表 6.3为测试计划的编写提纲。
1.引言
1.1编写目的
1.2背景
1.3定义
1.4参考资料
2.计划
2.1软件说明
2.2测试内容
2.3测试 1( 标识符 )
2.3.1进度安排
2.3.2条件
2.3.3测试资料
2.3.4测试培训
2.4测试 2(标识符)
……
表 6.3 测试计划的编写提纲
3.测试设计说明
3.1测试 l( 标识符 )
3.1.1控制
3.1.2输入
3.1.3输出
3.1.4过程
3.2测试 2( 标识符 )
……
4.评价准则
4.1范围
4.2数据整理
4.3尺度续表
2,测试分析报告测试分析报告的编写是为了把组装测试和确认测试的结果、
发现及分析写成文件加以记载,具体的内容要求如表 6.4所示。
1.引言
1.1编写目的
1.2背景
1.3定义
1.4参考资料
2.测试概要
3.测试结果及发现
3.1测试 1( 标识符 )
3.2测试 2( 标识符 )
……
4.对软件功能的结论
4.1功能 1( 标识符 )
4.1.1能力
4.1.2限制
4.2功能 2( 标识符 )
5.分析摘要
5.1能力
5.2缺陷和限制
5.3建议
5.4评价
6.测试资源消耗续表
6.2 调 试
6.2.1 调试方法软件测试的目的是发现程序中是否有错误,错误在什么位置以及错误的原因 。 发现错误后应进行调试 。 调试工作包含两个方面:一是查找错误的位置和原因,二是改正错误 。
查找错误的位置和原因是调试工作的重点,本节着重介绍如何确定错误的位置 。
测试中发现程序的运行结果与预期结果不符,仅从运行结果往往无法判断,因此在调试程序时一般都会采取一些方法以获得更多的信息。常用的一些调试方法有:
1) 输出存储器内容这种方法一般在调试汇编语言编写的程序时使用 。 通过输出存储器的内容获取程序运行出现错误的现场,然后进行分析研究,判断出错的原因 。 这种方法由于输出信息量极大,
而且输出的是某一时刻状态,不能动态反映程序的执行情况,
往往很难从中查找出错误的原因 。
2) 打印语句在程序中插入打印语句输出关键变量在程序运行过程中的动态值,可以检验在某个事件后,变量是否按预期的要求发生变化。这种方法需要修改源程序插入打印语句,可用于模块测试或小型程序的调试。
3) 自动调试工具利用调试工具来分析程序的动态行为 。 目前大部分的开发环境都提供一定的调试功能,也可以选择一些独立的调试工具软件 。
一般调试工具提供的调试功能主要有:变量值观察与修改、单步跟踪、设置断点等。可以在执行过程中观察变量的动态变化。
6.2.2 调试策略
1) 试探方法分析测试结果,猜想错误发生的大致位置,再用前面介绍的调试方法确定出错位置 。 这种方法效率一般很低 。
2) 回溯法这是一种对小型程序很有效的调试方法。从错误发生征兆的位置开始,人工往回追溯源程序代码,直到征兆消失为止,进而找出错误的原因。
3) 归纳法从一些线索(错误的迹象可能存在于一种或多种测试用例的结果中)着手,分析寻找它们之间的联系,提出对错误原因的假设,
然后再证明或否认假设。归纳法的工作过程如图 6.6所示。 收集信息 研究信息间的联系提出假设验证改正 改正错误 证明假设成功不成功能证明无法证明无法做出假设图 6.6 归纳法调试过程
4) 演绎法演绎法与归纳法过程相反,它首先列举出一些可能的原因和假设,然后根据测试结果对列出的错误原因进行排除,分析余下的错误原因,不能确定就留下继续分析,可确定就排除错误。剩余不可确定的原因,再增加测试数据,重复测试过程,直到故障排除。图 6.7是演绎法实施的过程。
列出可能的原因排除不正确的原因分析余下的错误原因确定原因纠错收集更多测试数据剩余错因 能证明不能证明图 6.7 演绎法调试过程
6.3 系 统 实 施
6.3.1 人员及岗位培训系统实施是系统开发的最后一个阶段,将系统设计阶段的结果在计算机上实现 。 系统实施阶段的主要任务除了前面的章节中已介绍的程序设计与调试外,还包括计算机硬件设备的购置和安装调试,操作人员的培训和系统切换及试运行 。
为用户单位培训系统操作,维护,运行管理人员是信息系统开发过程中不可缺少的重要环节 。 对人员的培训工作应该尽早进行,一方面是因为系统开发的各个阶段都必须有用户参加,尽早培训可以更好地使系统分析人员与用户进行沟通;另一方面,系统集成测试之后将投入试运行和实际运行,用户接受培训后可以更好地配合开发人员进行系统测试 。 一般对操作人员的培训与编程和调试工作同时进行,培训的主要内容包括:
① 系统整体结构,系统概貌;
② 系统分析设计思想和每一步考虑;
③ 系统输入方式和操作方式的培训;
④ 可能出现的故障以及故障的排除;
⑤ 系统文档资料的分类以及检索方式;
⑥ 数据的收集,统计渠道,统计口径等;
⑦ 运行操作注意事项等 。
如果系统用户对计算机技术不甚了解,对信息系统缺乏基本的认识,则在系统开发早期还应对用户进行 MIS及计算机基本知识的培训,在系统试运行前还应对计算机系统的基本操作、汉字输入方法等进行培训。
6.3.2 试运行和系统转换系统实施的最后一个阶段就是新系统的试运行和新老系统的转换 。 系统试运行阶段的主要工作包括:
① 系统的初始化,输入原始数据记录;
② 记录系统的运行数据和运行状况;
③ 核对新系统和老系统 ( 人工或计算机系统 ) 的输出结果;
④ 对实际系统的输入方式进行考查 ( 是否方便,效率如何,安全可靠性,误操作保护等 ) ;
⑤ 对系统实际运行、响应速度(包括运算速度、传递速度、查询速度、输出速度等)进行实际测试。
为特定用户开发的专用信息系统一般在系统组装完成后即进入试运行,试运行阶段的工作包含了对系统进行确认测试和系统测试的任务 。
新系统开发完成后最终要代替老系统,完成系统的切换 。
系统切换有三种方式:
1) 直接切换在确定新系统运行准确无误时,立刻启用新系统,终止老系统的运行。这种方式节省人员和设备费用,适用于一些处理过程不太复杂、数据不很重要的场合。
2) 并行切换新老系统并行工作一段时间,经过一段时间的考验后,新系统正式替代老系统。对于较复杂的大型系统,
这种方法提供了一个与旧系统运行结果进行比较的机会,
可以对新旧两个系统的时间要求、出错次数和工作效率给以公正的评价。由于与旧系统并行工作,用户消除了尚未认识新系统之前的惊慌与不安。这种方式的主要特点是安全、可靠,但费用和工作量都很大。
3) 分段切换这种切换方式是上面两种方式的结合。在新系统正式运行前,一部分一部分地替代老系统。切换过程中没有正式运行的那一部分,可以在一个模拟环境中进行考验。这种方式既保证了可靠性,又不至于费用太大。但是这种分段切换对系统的设计和实现都有一定的要求,
否则无法实现这种分段切换。
图 6.8是上面三种方式的示意图 。
老系统新系统切换 时间老系统新系统并行 时间老系统新系统分段区间 时间
( b ) 并行切换 ( c ) 分段切换( a ) 直接切换图 6.8 系统切换的三种方式
6.4 系 统 维 护
6.4.1 维护的内容信息系统实施之后,由于各种各样因素的影响,
例如系统运行环境的变化或者程序中存在未检测到的错误等,为了保证系统的正常工作,要求系统不断地完善并能适应各种变化,还需要进行系统的维护工作 。
系统维护的工作内容大致包括:
(1) 软件的维护:运行中发现软件测试阶段未发现的错误,或者用户对系统的功能要求发生变化,以及业务量的急剧增长等都有可能需要对软件进行修改 。
(2) 数据文件及代码的维护:随着系统的变化,原有的数据文件或代码不能适应新的需要,需要维护数据文件或修改旧的代码系统 。
(3) 硬件的维护:包括计算机,网络及相关设备的日常管理和维护工作 。 一旦硬件发生故障,必须有专门的人员进行修理 。
(4) 机构和人员的变动:机构和人员的变动有时也会对信息系统的流程和对设备及程序的维护工作产生影响。
6.4.2 软件维护的分类软件维护是信息系统维护的主要工作,软件工程学科将软件维护定义为,对现有运行软件进行修改而同时保留其主要功能不变的过程,。 通常软件维护工作可分为四类:
1) 改正性维护软件测试不可能将所有潜在的错误都查找出来,设计再好的测试用例也难免存在遗漏。运行中必然会发现软件错误,需要维护人员进行调试并改正错误。这类维护工作称为改正性维护或纠错性维护。
2) 适应性维护计算机系统硬件及操作系统的更新换代频繁,而一个大型的信息系统软件开发常常需要耗费巨资,因为系统运行环境的改变而废弃不用是很不合算的 。 因此要求维护人员对原来的软件进行修改,以适应新的软硬件运行环境的要求 。 这类维护活动称为适应性维护 。
3) 完善性维护当系统投入使用之后,用户会提出增加新功能,修改已有的功能以及一般的改进和建议 。 为了满足和部分满足这类要求,所进行的维护活动称为完善性维护 。 完善性维护占软件维护工作的大部分 。
4) 预防性维护为了给未来的改进奠定更好的基础而修改软件的维护活动称为预防性维护 。 这类维护活动相对较少 。
维护工作的多少和难易程度取决于软件设计的水平,软件开发应该注意按照软件工程方法的要求进行,以提高软件的可维护性 。 软件的可维护性由维护人员理解,改正,改动和改进软件的难易程度来衡量 。 开发过程的每个阶段必须有完备一致的文档资料,在设计软件结构时应注意提高模块之间的独立性 。
完备一致的文档资料有助于维护阶段阅读理解程序,对软件维护之后相应的文档资料也应该进行修改以保持软件与文档的一致性 。 模块之间的独立性可以避免维护工作中对某一个模块的修改而影响到系统中的其它模块 。
完善性维护
5 0 %
改正性维护
2 1 %
适应性维护
2 5 %
其它
4 %
图 6.9 四种维护工作量的分布
6.4.3 维护的管理系统的各项维护工作都应有专人负责,并且通过一定的审批手续 。
系统硬件维护的管理相对简单,本节我们主要讨论软件维护的管理,
因为软件维护相对影响较大,例如一个业务处理过程的修改,往往会影响其它过程或子系统 。
软件维护工作应由相对固定的维护组织来承担,一般应少吸收设计人员参加 。 这样可以促使设计人员在设计时注意提高软件的可维护性,另一方面不会影响设计人员从事新项目的开发工作 。
软件维护首先由系统操作的各类人员或业务管理人员提出对某项工作的要求,申请形式可以是书面报告或填写专门的维护申请表。维护要求被批准后,系统管理员组织维护人员实施维护,软件维护的工作流程可参考图 6.10。
类型估量错误严重程度评价优先级开始分析问题计划修改进度维护任务开始分析复审改正性适应性完善性不严重严重分配人员分配人员开发目录低高错误修改目录维护要求修改后的软件图 6.10 软件维护工作流程维护要求按其类型分成两条不同的处理路线 。 对于适应性和完善性维护来说,其性质与开发工作类似 。
对每次的软件维护活动都应作出维护记录,并存入软件维护数据库中 。 维护记录一般包含下面的一些内容:
● 程序标识;
● 源语句数;
● 使用的程序设计语言;
● 程序安装的日期;
● 自从安装以来程序运行的次数;
● 自从安装以来程序失效的次数;
● 程序改动的层次和标识;
● 因程序修改而增加的源语句数;
● 因程序修改而删除的源语句数;
● 每个改动所耗费的人时数;
● 程序修改的日期;
● 软件维护工程师的姓名;
● 维护要求表的标识;
● 维护类型;
● 维护开始和完成的日期;
● 累计用于维护的人时数;
● 该维护完成所带来的纯效益 。
6.5 实 验 五
6.5.1 实验目的安排本次实验的主要目的为:
① 熟悉单元测试和集成测试的主要任务;
② 掌握白盒测试和黑盒测试设计测试用例的主要方法;
③ 学习编写测试计划和测试报告;
④ 熟悉集成测试的主要步骤;
⑤ 熟练掌握常见开发工具的调试功能的使用方法,积累程序调试的经验。
6.5.2 实验内容对实验四中编写的各个模块的代码分别进行单元测试,排除错误,然后编写集成测试计划,进行集成测试,
最后编写测试报告。
6.5.3 实验步骤本次实验分以下几步:
① 小组内成员交换阅读各自编写的程序代码,对照常见错误表检查是否存在错误;
② 编写各模块的驱动模块和桩模块;
③ 准备各模块的条件组合覆盖或路径覆盖的测试用例;
④ 测试各模块,检查测试结果,排除错误;
⑤ 准备集成测试的测试用例 ( 等价类划分法,边界值分析法 ) ;
⑥ 编写集成测试计划;
⑦ 进行集成测试;
⑧ 编写测试报告。
6.1 软 件 测 试
6.2 调 试
6.3 系 统 实 施
6.4 系 统 维 护
6.5 实 验 五
6.1 软 件 测 试
6.1.1 测试的基本概念软件测试是对软件计划,软件设计,软件编码进行查错和纠错的活动 。 测试的目的是为了找出软件开发过程中各个阶段的错误,以便分析错误的性质和确定错误的位置,并纠正错误 。
软件测试伴随着程序设计的出现而出现,随着软件技术的发展,人们对软件测试的认识也在不断加深 。 通常人们认为,软件测试是为了证明软件是正确的,。 实际上这种认识是错误的 。 1983年,IEEE提出的软件工程标准术语中软件测试的定义是:,使用人工或自动手段来运行或测定某个系统的过程,其目的在于检验它是否满足规定的需求,或弄清预期结果与实际结果之间的差别,。 G.J.Myers则认为,程序测试是为了发现错误而执行程序的过程,。
上面的两种定义有不同的强调方面,关于软件测试的概念,我们要注意以下两点:
(1) 软件测试是为了发现程序中的错误而不是证明程序的正确性 。
按照 Myers的观点,,成功的测试是发现了至今尚未发现的错误的测试,。 当然测试的目的不仅仅是发现错误,还包含检验,评价等 。
(2) 软件测试方法不仅仅是执行程序,也包括人工方法。事实上,
人工测试在某些测试阶段可以发现大部分的错误。
6.1.2 测试的基本原则要高质量地完成测试工作,找出软件中的错误,应该遵守下面的一些基本原则:
(1) 测试队伍与开发队伍应分别建立 。
开发和测试工作两者在思想和方法上都是不一样的,为了保证测试的质量,应分别建立开发和测试队伍。开发工作是建设性的,而在测试阶段,人们设计出一系列的输入数据(称为测试用例),目的是为了
“破坏”已经建造好的软件。就像给硬件产品做高低温试验、震动试验、
破坏性试验一样。而且一般程序编写者往往认为自己编写的程序是正确的,要他们找出自己程序中的错误是十分困难的。
(2) 设计测试用例时,要给出测试的预期结果 。
一个测试用例应由两部分组成:
① 对程序进行测试的一组输入数据的描述;
② 由这一组输入数据所产生的程序的预期输出结果的描述 。
预期输出结果不一定是精确的输出结果,对于一些复杂的计算,
人工计算结果可能需要很大的工作量,可以给出一个对输出结果有效范围的描述 。
(3) 设计测试用例时,应包括对有效的和期望的输入条件的测试,
也应包括对无效的和非期望的输入条件的测试 。
一个程序不仅当输入合法时能正确运行,而且当有非法输入时,
应该能够拒绝这些非法输入,并给出适当的提示信息。
(4) 在程序修改之后,要进行回归测试 。
对程序的任何修改都有可能引入新的错误,所以必须进行回归测试,即将以前的所有测试用例再次输入测试,而不是仅仅测试以前结果不正确的测试用例 。 回归测试有助于发现由于修改程序而引入的新错误 。
(5) 对发现错误较多的程序段,应进行深入的测试 。
如果发现某个程序段错误较多,则表明这个程序段质量很低,有可能隐藏有更多的错误,应该进行深入的测试。
6.1.3 测试方法软件测试方法有多种,这些测试方法具有不同的思路和出发点 。 总的来说,测试方法可分为静态测试方法和动态测试方法两大类 。
所谓静态测试方法,是指不在计算机上运行被测试程序,
而是采用其它手段达到对程序进行检测目的的测试方法 。 静态测试方法包括人工测试方法和计算机辅助静态分析方法 。
所谓动态测试方法,是指在计算机上运行被测试程序,
并用所设计的测试用例对程序进行检测的方法 。 动态测试方法根据设计测试用例的思想不同可分为白盒测试,黑盒测试以及穷举测试等 。
1,人工测试方法人工测试方法是指依靠人而不是计算机来对程序进行检测的方法 。
人工测试可以找出计算机测试不容易发现的错误,可以减少系统测试的总工作量 。 根据统计,人工测试能有效地发现 30%~70%的逻辑设计和编码错误 。
人工测试可以采用人工运行和代码审查的方式 。 代码审查可以由程序编写者本人非正式地进行,也可以由审查小组正式进行 。 代码审查主要是对照常见程序错误清单对程序代码进行分析审查,并将发现的错误记录下来 。
表 6.1是由 Myers提供的常见程序错误清单,该表主要针对
FORTRAN一类的程序设计语言所编写的程序,其它的程序设计语言编写的程序也可参照该清单。表中的参数相当于 C语言中函数的形式参数,而变元相当于 C语言中函数调用时的实际参数。
表 6.1 Myers提供的常见程序错误清单一、模块接口检查表
1.模块接收的输入参数个数与模块的变元个数是否一致?
2.参数与变元的属性是否匹配?
3.参数与变元所用的单位是否一致?
4.传送给被调用模块的变元的数目是否等于那个模块的参数的数目?
5.传送给被调用模块的变元属性和参数的属性是否一致?
6.传送给被调用模块的变元的单位和参数的单位是否一致?
7.传送给内部函数的变元属性,数目和次序是否正确?
8.是否修改了只是作为输入用的变元?
9.全程变量的定义在各个模块中是否一致?
10.有没有把常数当作变量来传送?
二、完成外部输入 /输出时的检查表
4,文件属性是否正确?
2.打开文件语句是否正确?
3.格式说明与输入 /输出语句给出的信息是否一致?
4.缓冲区大小与记录大小是否匹配?
5.是否所有文件在使用前都已打开了?
6.对文件结束条件的判断和处理是否正确?
7.对输入 /输出错误的处理是否正确?
8.输出信息中有没有正文错误?
三、模块局部数据结构的检查表
4,有没有不正确或不一致的说明?
2,有没有不正确的初始化和缺省值?
3,有没有错误的变量名?
4,有没有不相容的数据类型?
5,有没有下溢,上溢或地址错误?
四、计算错误检查表
4,对运算优先次序的错误理解或错误处理 。
2.发生了混合运算 ( 运算对象的类型不相容 ) 。
3.初始化错误 。
4.计算精度不够 。
5.表达式的符号表示错误 。
五、比较错误的检查表
4,不同数据类型的数据进行比较 。
2.逻辑运算符或其优先次序用错 。
3.本应相等的数据,由于精度原因而不相等 。
4.变量本身有错或比较有错 。
5.循环终止不正确或循环不止 。
6.“差 1”错 ( 多一次或少一次循环 ) 。
7.当遇到发散的迭代不能摆脱出来 。
8.循环控制变量修改有错 。
六、出错处理的检查表
1.对错误的描述难以理解 。
2.指明的错误并非实际遇到的错误 。
3.出错后尚未进行错误处理,错误条件已引起了系统干预 。
4.对错误的处理不正确 。
5.提供的错误信息不足,以致无法找到出错的原因 。
人工测试还可以采用软件审查的方式,它可以用于系统开发的各个阶段,对产品的质量进行评审。限于篇幅,本书不再详细介绍。
2,计算机辅助静态分析方法计算机辅助静态分析方法是利用计算机测试工具对被测程序的特性进行分析方法的总称 。
静态分析工具主要有下面几种形式:
(1) 静态确认工具:对程序进行静态分析和确认,收集一些程序中的信息,以查找程序中的各种缺陷和可疑的程序构造 。 例如,使用了一个尚未赋值的变量,或者赋了值的变量一直没有使用等 。
(2) 符号执行工具:以符号值作为程序的输入,使程序符号执行,对程序的运算规律加以检验 。
(3) 程序验证工具:交互式程序验证系统是证明程序正确性的一种工具 。 它通过系统内部基于符号的逻辑变换和结构归纳,提取程序的语义和结构的要点来分析证明程序的正确性 。
3,黑盒测试黑盒测试又称功能测试,即不管程序内部是如何编制的,只考虑程序输入和输出之间的关系,或只考虑程序的功能 。 因此,测试者必须根据软件的规格说明书来确定和设计测试用例 。 黑盒测试也被称为数据驱动测试或基于规格说明书的测试 。
黑盒测试适合于对内部结构未知的软件进行测试,例如对于外购的软件包,只能根据软件包的功能说明书进行测试 。 另外,用户对系统的验收测试也使用黑盒测试方法,因为用户关心的是软件是否能实现所需的功能 。 也可以说,黑盒测试是从用户观点进行的测试 。
4,白盒测试白盒测试也称为结构测试,它是根据被测试程序的逻辑结构设计测试用例。使用白盒测试方法需要了解程序的内部结构,对程序的不同逻辑路径进行测试。由于采用不同方法设计测试用例对程序的逻辑路径覆盖的程度不一,白盒测试又被称为基于“覆盖”的测试。覆盖率越高,
测试越充分。
5,穷举测试软件测试的主要目的是查找软件中存在的错误,而不能证明软件的正确性 。 实际上采用一般的测试方法根本无法证明软件的正确性 。 有人主张通过白盒或黑盒测试方法对所有可能的情况进行测试,如果所有的情况都是正确的,则可证明程序是正确的 。 这种方法被称为穷举测试,
实际上除了一些简单的程序外,它是无法实现的 。
使用黑盒测试进行穷举测试,必须穷举所有可能的输入数据 。 举一个简单的例子,假设输入三个无符号整数作为三角形的三条边长,判断该三角形是否为直角三角形 。 C语言中无符号整数的范围为 0~216-1,如果要穷举所有的输入数据,则测试用例数为 216*216*216≈3*1014,假定程序每执行一次需要 1 ms,则需要一万年 。
白盒测试要实现穷举测试同样难以实现,当程序中包含有较复杂的循环和条件语句嵌套时,可能的执行路径数目同样很多,测试用例要覆盖所有的执行路径是根本不可能的。
6.1.4 设计测试用例使用白盒测试和黑盒测试都需要设计测试用例,上一节中已经提到要将所有可能的情况穷举出来是不可能的,因此在设计测试用例时必须依据一定的原则,以保证既能对程序进行充分的测试,而测试用例的数目又不能太大 。 本节将介绍常用的白盒和黑盒测试用例设计的方法 。
1,白盒测试白盒测试根据模块设计阶段对模块内部逻辑结构的描述设计测试用例。根据测试用例对模块所有可能执行路径的覆盖程度,可将其分为语句覆盖、判定覆盖、条件覆盖、判定条件覆盖、条件组合覆盖和路径覆盖。
1) 语句覆盖语句覆盖要求所设计的用例使程序中的每一条语句至少执行一次 。
这是覆盖程度很低的一种覆盖标准 。 下面是一个简单的例子 。
假设程序的流程图如图 6.1所示,对应的 C语言源程序片段如下:
X=0;
if(A>1||B>2)
X=A+B;
printf(,%d”,X);
现在按语句覆盖标准设计测试用例,
只需设计一组测试用例使条件
,A>1 or B>2”成立即可,例如:
输入数据,A=2,B=0;
输出数据,X=2。
A > 1 o r B > 2
X = A + B
输出 X
X = 0
图 6.1 被测试程序的流程图这组测试用例虽然覆盖了所有的语句,但对条件语句的分支测试不充分,只测试了条件为真的分支。
如果条件表达式中的第一个条件表达式 A>1误写为
A=1( C语言中该表达式值为真),这组测试用例无法检测该错误。同样,如果条件表达式中的第二个条件表达式 B>2写错,这组测试用例也不能检测出程序的错误。
2) 判定覆盖判定覆盖要求对程序中所有判定的分支都必须能够执行到 。 对于上面的例子,可设计两组测试用例:
第一组输入数据,A=2,B=0; 输出数据,X=2;
第二组输入数据,A=1,B=0; 输出数据,X=0。
这两组测试用例分别使条件语句中的条件表达式取,真,和,假,,
很显然也是语句覆盖,但对程序的测试比语句覆盖更充分 。
判定覆盖也是一种较弱的覆盖,这里的例子对条件表达式中 B>2
的测试很不充分,没有测试该表达式为真的情况。
3) 条件覆盖条件覆盖是指设计的测试用例能使程序中判定的每一个条件的可能取值都满足一次 。
对于上面的例子,判定中有两个条件,每个条件的可能取值为:
条件 1,A>1 真 记为 T1
假 ( A≤1) 记为 F1
条件 2,B>2 真 记为 T2
假 ( B≤2) 记为 F2
可以设计两组测试用例:
第一组输入数据,A=2,B=3; 输出数据,X=2;满足 T1,T2;
第二组输入数据,A=1,B=0; 输出数据,X=0;满足 F1,F2。
在大部分情况下,条件覆盖比判定覆盖强,因为它使判定表达式中每个条件都取得了可能的值,而判定覆盖只关心整个判定的取值 。 读者可以很容易地看出,这里的两组测试用例也满足判定覆盖的要求 。
但条件覆盖并不一定总是满足判定覆盖的要求,对上面的例子,我们看下面的两组测试用例:
第一组输入数据,A=2,B=0; 输出数据,X=2;满足 T1,F2;
第二组输入数据,A=1,B=3; 输出数据,X=4;满足 F1,T2。
这两组测试用例虽然满足条件覆盖的要求,但它不满足判定覆盖的要求。
4) 判定 /条件覆盖判定 /条件覆盖是指设计足够的测试用例,使其既满足条件覆盖的要求又满足判定覆盖的要求 。 要求判定中每一个条件所有的取值都能满足一次,而且保证判定的每个分支都能执行到一次 。 很显然,判定 /条件覆盖比前面的几种覆盖标准更强 。
判定 /条件覆盖仍然有一定的不足,表面看起来它测试了所有条件的所有可能取值,但实际上往往有某些条件掩盖了另一些条件。假设判定由两个条件构成,例如,x and y”。如果 x取值为“假”,不管此时 y的取值为“真”还是为“假”,整个判定的值均为“假”。
5) 条件组合覆盖条件组合覆盖是指设计足够的测试用例,使得判定中各种条件可能的取值组合都能满足一次 。
对上面例子中的程序,判定中共有两个条件表达式,每个条件都有两种取值,因此共有四种取值组合,它们是:
① A>1,B>2;
② A>1,B≤2;
③ A≤1,B>2;
④ A≤1,B≤2。
请读者自行设计四组输入数据分别满足不同的取值组合,本书不再赘述 。
很显然,条件组合覆盖的测试用例必定满足判定 /条件覆盖,条件覆盖和判定覆盖的要求 。
6) 路径覆盖路径覆盖是指设计足够的测试用例,使其覆盖程序中所有可能的路径 。
前面在介绍穷举测试时,
我们提到对于一些含有复杂条件和循环嵌套的程序,其可能路径的数目很大,路径覆盖是无法实现的。对于一些简单的程序,路径覆盖还是可以实现的,我们看图 6.2所示的程序流程示意图。
s
a
b
c d
e
图 6.2 被测程序的流程图该流程图中共有两个判定,程序执行的所有可能的路径共有 4种:
sace,sade,sbce和 sbde。
对于一些含有循环及条件嵌套的程序,由于其可能的执行路径数目巨大,要实行真正的路径覆盖是不可能的。对于这样一些程序,
可以采取一些方法来简化测试用例的设计,例如通常可以将循环简化为进入循环和不进入循环的分支操作,则执行路径的数目将大大减少。
2,黑盒测试黑盒测试是根据功能说明书进行的测试,测试者只知道程序的输入和输出之间的关系或程序的功能 。 测试者必须仔细地研究程序的功能说明,找出程序的功能信息或输入和输出之间的关系,然后设计测试用例并推断测试结果的正确性 。 常用的黑盒测试方法有等价类划分,
边界值分析等 。
1) 等价类划分等价类划分是黑盒测试常用的一种方法 。 它的基本思想是:将所有可能的输入情况划分为若干个等价类,然后为每一个等价类设计一个测试用例,如果这个测试用例程序的输出结果是正确的,则认为对该类的所有数据该程序都能得到正确的输出结果 。
等价类划分方法测试的质量取决于等价类划分是否合理,这往往依赖于测试人员的经验。下面是等价类划分经常采用的一些规则:
(1) 如果规定了输入值的范围或值的个数,则取一个有效等价类,两个无效等价类 。 例如功能说明书规定,项数为 1~10”,则取一个有效等价类,项数在 1~10之间,,两个无效等价类,项数 <1”和,项数 >10”。
(2) 如果输入项规定了值的集合,则取一个有效等价类和一个无效等价类 。 例如规定电话号码,以数字开头,,则取一个有效等价类,以数字开头,,一个无效等价类,以字母或其它字符开头,。
(3) 如果规定了输入数据的一组值,而且程序对不同输入值进行不同处理,则每个允许的输入值分别是一个有效等价类,此外还有一个无效等价类。
(4) 如果规定了输入数据的规则,则取符合规则的一个有效等价类和若干不符合规则的无效等价类 。
(5) 如果规定了输入数据是整形,则可以划分出负整数,零,正整数三个等价类 。
以上只是一些可供参考的规则,实际工作中应仔细分析程序输入数据的要求,划分出有代表性的有效等价类和无效等价类 。
在确定输入数据的等价类时,常常还需要分析输出数据的等价类,
以便根据输出数据等价类导出输入数据的等价类。例如,输入三角形的三条边长,判断三角形是普通三角形、等腰三角形还是等边三角形,
在设计等价类时显然应根据输出结果进行等价类的划分。
在划分有效等价类之后,按照等价类设计测试用例时应该注意:
(1) 设计一个测试用例,使其覆盖尽可能多的尚未覆盖的有效等价类 。
(2) 设计一个测试用例,使其只覆盖一个无效等价类 。
之所以如此要求,是因为经验表明,程序员往往更注意有效输入,
而忽视对无效输入数据的处理 。
现在来看一个简单的例子 。 假设程序要求输入某城市的电话号码,
电话号码由三个部分构成 。 这三个部分的名称与内容分别是:
地区码:空白或三位数字;
前缀:非 ‘ 0’或 ‘ 1’开头的三位数字;
后缀:四位数字 。
假定被测试的程序接收符合上述规则的所有号码,拒绝所有不符合规则的号码 。 现在使用等价类划分法来对其进行测试 。
第一步,划分等价类 。 划分的等价类以表格形式 ( 表 6.2) 给出,并给每个等价类一个唯一的编号 。
输入条件 有效等价类 无效等价类地区码 空白⑴,3位数字⑵ 有非数字字符⑸,少于 3位数字⑹,多于 3位数字⑺
前 缀 从 200到 999之间的数字⑶
有非数字字符⑻,起始位为‘ 0’
⑼,起始位为‘ 1’⑽,少于 3位数字⑾,多于 3位数字⑿
后 缀 4位数字⑷ 有非数字字符⒀,少于 4位数字⒁,多于 4位数字⒂
表 6.2 电话号码的等价类划分第二步,确定测试用例 。 表中有四个有效等价类,可使用下面两个测试用例:
测试数据 测试范围 期望结果
( ) 276-2345 等价类 ⑴⑶⑷ 有效
( 635) 805-9321 等价类 ⑵⑶⑷ 有效对于 11个无效等价类,应选择 11个测试用例 。 限于篇幅,这里不再一一给出 。
2) 边界值分析法在等价类划分法中,代表一个等价类的测试数据可以在这个类的允许值范围内任意选择 。 假设输入数据 x的有效范围为 [1.0,10.0],则设计测试用例时,有效等价类的输入数据可为 1~ 10之间的任意数据,
例如 2.0。 如果程序员将 x>=1.0错写为 x>1.0,则所选定的测试用例将不能检测到这类错误 。 如果选择有效范围的边界上的测试用例,则对这类错误的测试效果将很好,这就是边界值分析的基本思想 。
各种资料和经验也表明,程序员在程序设计过程中往往对输入输出数据有效范围的边界不够重视,在处理边界情况时,程序最容易发生错误 。 使用边界值分析方法设计测试用例,暴露程序错误的可能性将更大 。
在对边界值进行分析,进行测试用例设计时,可参考下面的一些规则:
(1) 如果输入条件规定了取值范围,则应对该范围的边界内附近,恰好在边界上和边界外附近设计测试用例 。
例如,规定输入值的有效范围为 [1.0,10.0],则应对 0.9,1.0,1.1,9.9、
10.0,10.1设计测试用例 。
(2) 如果输入条件规定了数据的个数,则应对最小个数,最大个数,比最小个数少 1,比最大个数多 1等情况设计测试用例 。
(3) 对软件规格说明中的每一个输出条件仿照前面对输入条件使用的
( 1),( 2) 原则设计测试用例 。
边界值分析法通常不作为一种独立的测试方法,而是作为其它测试方法的一种补充 。 例如,使用等价类划分法设计测试用例后,再使用边界值分析法补充部分测试用例对边界情况进行测试 。
黑盒测试方法除了上面介绍的两种之外,常见的还有因果图,错误推测法和判定表驱动测试等 。 本书在此不进行详细介绍 。
6.1.5 测试过程与步骤软件测试的过程如图 6.3所示。
软件测试构造测试测试结果预期结果评价 纠错错误错误率数据可靠性模型可靠性预测修正的软件图 6.3 软件测试的过程图 6.3中的输入有两类,即:
(1) 软件,即待测试的软件,包括设计阶段相关的文档和源程序清单等 。
(2) 测试构造,包括测试计划,测试用例及预期的测试结果 。
将得到的测试结果与预期结果比较,如果不符,则意味着错误,需要纠正,经过纠错后的软件需要再进行回归测试,如此反复地进行;
如果相符,则根据测试过程中错误发生的情况建立可靠性模型,作为系统付诸实施后的维护工作的依据 。 这一点正如前面所讲的,测试的目的并不是证明软件的正确性,测试通过的软件仍然可能含有错误 。
大型软件的测试工作一般分为模块测试、集成测试、确认测试和系统测试四个阶段。下面我们对每个阶段的主要内容和方法进行简单的介绍。
6.1.6 模块测试程序模块是构成信息系统中软件部分的基本单位,模块的测试是信息系统软件测试的第一步 。 模块测试又叫单元测试,经验表明模块测试发现的错误占错误总数的 65%,其重要性显而易见 。 一个模块具有以下属性:
① 名字;
② 应完成的功能;
③ 实现功能所应采用的算法;
④ 内部使用的数据结构;
⑤ 模块接口 。
一个模块可被其它模块调用,因此要接收输入参数,并在该模块执行完成后给调用模块返回输出参数。该模块在执行过程中也可能调用其它模块,因此需要输出数据作为被调用模块的输入参数,并接收被调用模块返回的输入数据。
1,模块测试的内容模块测试针对模块的各项属性进行检验测试,主要内容有:
1) 模块接口测试在测试模块的其它属性之前,首先应对穿过模块接口的数据进行测试 。
如果数据不能正确地在模块之间传递,其它的动态测试将不能正常进行 。
在对模块接口进行测试和检验时,应着重参照 Myers提供的常见程序错误清单中的“模块接口检查表”和“完成外部输入 /输出时的检查表”来逐项检查。
2) 局部数据结构对于一个模块来说,局部数据结构通常是错误的发源地,应该设计相应的测试用例,以便发现下列类型的错误:
① 不一致或不正确的说明;
② 错误的初始化或错误的缺省值;
③ 不相容的数据类型;
④ 上溢,下溢和地址异常 。
除了局部数据结构外,如有可能,在模块测试期间也应检查全局数据对模块的影响 。
3) 覆盖条件和路径测试在单元测试期间,必须对重要模块的基本路径进行测试 。 应设计测试用例,用来发现由于不正确的计算,比较或不适当的控制流而造成的错误 。
计算中常见的错误有:
① 算术运算优先次序不正确或误解了运算次序;
② 运算方式不正确;
③ 初始化不正确;
④ 精度不够;
⑤ 表达式的符号表示不正确 。
程序中的比较运算和控制流向关系密切,通常在比较之后发生控制流的变化。测试用例应发现下述错误:
① 不同数据类型的数据进行比较;
② 逻辑运算符不正确或优先次序不正确;
③ 因为精度问题造成期待相等的数据不相等;
④ 循环终止条件不正确;
⑤ 不正确地修改循环变量。
4) 错误处理良好的程序设计应能预先估计到运算中可能发生的错误和异常,例如误操作或不正确的输入数据,并给出相应的处理措施 。 在模块测试时,
应有意地进行不合理输入,检查程序的错误处理能力 。 主要注意检查如下几种情况:
① 输出的出错信息难以理解;
② 输出的出错信息与实际不符;
③ 错误处理不正确;
④ 在错误处理之前,错误已引起系统干预 。 操作系统一般都具有一定的错误捕获能力,但是它给出的错误信息一般比较笼统,应用程序应在操作系统捕获错误之前,对错误进行处理 。
5) 边界测试对输入输出数据的各种等价类边界,以及分支条件和循环条件的边界,
都应测试模块能否正确工作 。
2,模块测试的步骤与方法单元测试常被当作编码的附属步骤,当编码完成后,程序员首先进行初步检查,然后可由专门的测试人员或采用码审查会的形式来进行测试 。
在确认没有语法错误之后,可针对每个模块单独地进行测试工作 。
模块的动态测试采取白盒测试的方法,根据模块设计阶段得到的模块的逻辑结构设计测试用例 。
由于模块不是完整独立的程序,往往不能独立地运行,在整个系统中既可能被别的模块调用,也可能调用其它的模块 。 要进行动态测试,必须要模拟这两类关系以建立一个独立的测试环境 。 在单元测试过程中,
需要设计两类辅助测试模块来模拟这两类关系 。 用以模拟被测模块的上级调用模块称为驱动模块;模拟被测模块运行过程中所调用的模块称为桩模块 。
驱动模块的作用是:在单元测试中从外部接受测试数据;把测试数据转发给被测模块,运行被测模块;接受被测模块的测试结果数据;输出结果数据 。 驱动模块一般包含三种语句:输入语句,仿照其上级模块调用格式的调用语句,输出语句 。
桩模块用来代替被测模块所调用的模块 。 一般只需打印接口数据并返回,以便于检测被测模块与其下级模块之间的接口,有时也需要用最简单的方法来模拟它所替代的模块的动作 。
驱动模块和桩模块只是为测试而编写的,一般都很简单,测试工作结束后它们就没有用处了 。
模块测试阶段如果发现程序有错,错误一般发生在编码和模块设计阶段,应对编码和模块设计阶段的工作进行检查,改正错误后重新测试,
直至模块能完成规定的功能 。
6.1.7 集成测试模块测试完成后,每个模块能正常完成规定的工作 。 进一步的工作就是将所有模块组装起来构成一个完整的系统 。
1,集成测试的基本方法实践表明,单个模块能正常工作,并不能保证组装后也能正常工作 。
常见的原因有:
① 模块间的接口未经过严格测试,可能存在错误;
② 一个模块可能会破坏另一个模块的功能;
③ 把子功能组合起来不能产生预期的主功能;
④ 单个模块可以接受的误差在组装后累计放大,超出可接受的程度 。
鉴于以上的原因,在模块的组装过程中必须进行测试,称为集成测试或组装测试。集成测试的主要目的是发现与接口有关的错误。
如果集成测试阶段发现错误,则可能是在总体设计阶段设计软件结构时模块之间接口定义有误 。
集成测试主要有非渐增式测试和渐增式测试两种方法 。
(1) 非渐增式测试的过程是:先对每个模块进行测试,再将所有模块按系统软件结构组装,然后进行测试 。 一般用黑盒测试法设计测试用例 。
(2) 渐增式测试的过程是:逐个将未经测试的模块组装到已经测试过的模块上,然后进行集成测试 。 它不严格区分模块测试和集成测试阶段 。
每加入一个新模块都进行一次测试,重复此过程直到系统组装完成 。
渐增式测试模块组装的顺序可分为自顶向下结合和自底向上结合两种方法。
1) 自顶向下结合自顶向下结合的方法是:按照软件结构图自顶向下进行结合,首先测试顶层模块,然后逐步加入下层模块。可采取先广度后深度逐层安装,
或者先深度后广度进行模块结合。自顶向下结合方法不需要编写驱动模块,因为模块被组装进来时,它的上层模块已安装好。
A
B C D
E F G
图 6.4所示的软件结构图采用先广度后深度逐层安装时,模块的安装顺序为 A→B→C→D→E→F→G ;
若采用先深度后广度结合方法,模块的安装顺序则为
A→B→E→C→F→D→G 。
图 6.4 软件结构图
2) 自底向上结合自底向上结合的方法是:按照软件结构图自底向上,逐步安装与测试,直到测试结束。图 6.4的软件结构测试过程如图 6.5所示,分三步组装测试(图中 di表示驱动模块)。自底向上的结合方式只需要驱动模块,不需要桩模块。
d1 d2 d3
E F G B C D
E F G
d4 d5 d6
B C D
E F G
A
图 6.5 自底向上结合
2,不同测试方法的比较非渐增式测试方法单元测试阶段使用的辅助模块较多,适合于较小规模的系统 。 而且如果系统规模很大,测试中若发现错误,错误的定位将非常困难 。
渐增式测试逐步组装系统,很容易发现错误发生在哪个模块,适合于大规模的系统 。
采用自顶向下结合可在程序测试的早期实现并验证系统的主要功能,
及早发现上层的接口错误,但对底层关键模块中的错误发现较晚 。 采用自顶向下结合不能多个测试小组同时工作,测试周期较长 。
采用自底向上测试的优缺点与自顶向下相反,可以及早发现底层关键模块中的错误,但到测试的后期才能看到系统的全貌 。 采用自底向上结合可以多个测试小组同时展开工作,测试不同的子系统 。
在实际测试工作中可以采取混合的测试策略,自底向上和自顶向下测试同时展开,对系统的上层采用自顶向下的组装方法,而对系统的中,
下层模块采用自底向上组装测试的方法 。
6.1.8 确认测试确认测试,也称为验收测试 。 在集成测试之后,软件已组装完成,
接口错误也已改正,下一步应该验证软件的有效性,由用户参与测试,
检验软件功能是否与用户的要求一致 。
确认测试通过黑盒测试法来证实软件的功能与用户要求是否一致 。
测试计划和测试过程的目标是:检查功能,性能要求是否达到,文档资料是否正确完整以及其它要求如可移植性,错误恢复能力和易维护性等是否满足 。
确认测试如果发现功能或性能与用户要求有差距,通常与需求分析阶段的差错有关 。 因涉及面较广,通常需要与用户协商来妥善解决 。
对于一些通用的软件,要求所有客户进行验收确认是不可能的 。 这类软件确认测试一般分为两个阶段,称为
Alpha( α) 测试和 Beta( β) 测试 。 Alpha测试在开发者的场所由用户在开发者关注和控制的环境下进行 。 Beta测试则是在一个或多个客户自己的场所由最终用户进行,开发者不到场 。 客户记录下测试中遇到的所有问题,试运行一个阶段后把这些问题报告给开发者 。
6.1.9 系统测试软件经过确认测试后,最终还要与系统中的其它部分配套运行 。 系统测试的任务就是测试软件与系统其它部分是否能正常配套工作 。 系统测试通常有以下几类测试:
(1) 恢复测试:
(2) 安全测试:
(3) 强度测试:
(4) 性能测试:
6.1.10 测试阶段的主要文档测试阶段的主要文档包括测试计划和测试分析报告 。
单元测试作为编码阶段的附带步骤,一般没有独立的文档,这里讲的测试主要是指整个程序系统的组装测试和确认测试 。
1,测试计划测试计划包括对每项测试活动的内容、进度安排、
设计考虑、测试数据的整理方法及评价准则。表 6.3为测试计划的编写提纲。
1.引言
1.1编写目的
1.2背景
1.3定义
1.4参考资料
2.计划
2.1软件说明
2.2测试内容
2.3测试 1( 标识符 )
2.3.1进度安排
2.3.2条件
2.3.3测试资料
2.3.4测试培训
2.4测试 2(标识符)
……
表 6.3 测试计划的编写提纲
3.测试设计说明
3.1测试 l( 标识符 )
3.1.1控制
3.1.2输入
3.1.3输出
3.1.4过程
3.2测试 2( 标识符 )
……
4.评价准则
4.1范围
4.2数据整理
4.3尺度续表
2,测试分析报告测试分析报告的编写是为了把组装测试和确认测试的结果、
发现及分析写成文件加以记载,具体的内容要求如表 6.4所示。
1.引言
1.1编写目的
1.2背景
1.3定义
1.4参考资料
2.测试概要
3.测试结果及发现
3.1测试 1( 标识符 )
3.2测试 2( 标识符 )
……
4.对软件功能的结论
4.1功能 1( 标识符 )
4.1.1能力
4.1.2限制
4.2功能 2( 标识符 )
5.分析摘要
5.1能力
5.2缺陷和限制
5.3建议
5.4评价
6.测试资源消耗续表
6.2 调 试
6.2.1 调试方法软件测试的目的是发现程序中是否有错误,错误在什么位置以及错误的原因 。 发现错误后应进行调试 。 调试工作包含两个方面:一是查找错误的位置和原因,二是改正错误 。
查找错误的位置和原因是调试工作的重点,本节着重介绍如何确定错误的位置 。
测试中发现程序的运行结果与预期结果不符,仅从运行结果往往无法判断,因此在调试程序时一般都会采取一些方法以获得更多的信息。常用的一些调试方法有:
1) 输出存储器内容这种方法一般在调试汇编语言编写的程序时使用 。 通过输出存储器的内容获取程序运行出现错误的现场,然后进行分析研究,判断出错的原因 。 这种方法由于输出信息量极大,
而且输出的是某一时刻状态,不能动态反映程序的执行情况,
往往很难从中查找出错误的原因 。
2) 打印语句在程序中插入打印语句输出关键变量在程序运行过程中的动态值,可以检验在某个事件后,变量是否按预期的要求发生变化。这种方法需要修改源程序插入打印语句,可用于模块测试或小型程序的调试。
3) 自动调试工具利用调试工具来分析程序的动态行为 。 目前大部分的开发环境都提供一定的调试功能,也可以选择一些独立的调试工具软件 。
一般调试工具提供的调试功能主要有:变量值观察与修改、单步跟踪、设置断点等。可以在执行过程中观察变量的动态变化。
6.2.2 调试策略
1) 试探方法分析测试结果,猜想错误发生的大致位置,再用前面介绍的调试方法确定出错位置 。 这种方法效率一般很低 。
2) 回溯法这是一种对小型程序很有效的调试方法。从错误发生征兆的位置开始,人工往回追溯源程序代码,直到征兆消失为止,进而找出错误的原因。
3) 归纳法从一些线索(错误的迹象可能存在于一种或多种测试用例的结果中)着手,分析寻找它们之间的联系,提出对错误原因的假设,
然后再证明或否认假设。归纳法的工作过程如图 6.6所示。 收集信息 研究信息间的联系提出假设验证改正 改正错误 证明假设成功不成功能证明无法证明无法做出假设图 6.6 归纳法调试过程
4) 演绎法演绎法与归纳法过程相反,它首先列举出一些可能的原因和假设,然后根据测试结果对列出的错误原因进行排除,分析余下的错误原因,不能确定就留下继续分析,可确定就排除错误。剩余不可确定的原因,再增加测试数据,重复测试过程,直到故障排除。图 6.7是演绎法实施的过程。
列出可能的原因排除不正确的原因分析余下的错误原因确定原因纠错收集更多测试数据剩余错因 能证明不能证明图 6.7 演绎法调试过程
6.3 系 统 实 施
6.3.1 人员及岗位培训系统实施是系统开发的最后一个阶段,将系统设计阶段的结果在计算机上实现 。 系统实施阶段的主要任务除了前面的章节中已介绍的程序设计与调试外,还包括计算机硬件设备的购置和安装调试,操作人员的培训和系统切换及试运行 。
为用户单位培训系统操作,维护,运行管理人员是信息系统开发过程中不可缺少的重要环节 。 对人员的培训工作应该尽早进行,一方面是因为系统开发的各个阶段都必须有用户参加,尽早培训可以更好地使系统分析人员与用户进行沟通;另一方面,系统集成测试之后将投入试运行和实际运行,用户接受培训后可以更好地配合开发人员进行系统测试 。 一般对操作人员的培训与编程和调试工作同时进行,培训的主要内容包括:
① 系统整体结构,系统概貌;
② 系统分析设计思想和每一步考虑;
③ 系统输入方式和操作方式的培训;
④ 可能出现的故障以及故障的排除;
⑤ 系统文档资料的分类以及检索方式;
⑥ 数据的收集,统计渠道,统计口径等;
⑦ 运行操作注意事项等 。
如果系统用户对计算机技术不甚了解,对信息系统缺乏基本的认识,则在系统开发早期还应对用户进行 MIS及计算机基本知识的培训,在系统试运行前还应对计算机系统的基本操作、汉字输入方法等进行培训。
6.3.2 试运行和系统转换系统实施的最后一个阶段就是新系统的试运行和新老系统的转换 。 系统试运行阶段的主要工作包括:
① 系统的初始化,输入原始数据记录;
② 记录系统的运行数据和运行状况;
③ 核对新系统和老系统 ( 人工或计算机系统 ) 的输出结果;
④ 对实际系统的输入方式进行考查 ( 是否方便,效率如何,安全可靠性,误操作保护等 ) ;
⑤ 对系统实际运行、响应速度(包括运算速度、传递速度、查询速度、输出速度等)进行实际测试。
为特定用户开发的专用信息系统一般在系统组装完成后即进入试运行,试运行阶段的工作包含了对系统进行确认测试和系统测试的任务 。
新系统开发完成后最终要代替老系统,完成系统的切换 。
系统切换有三种方式:
1) 直接切换在确定新系统运行准确无误时,立刻启用新系统,终止老系统的运行。这种方式节省人员和设备费用,适用于一些处理过程不太复杂、数据不很重要的场合。
2) 并行切换新老系统并行工作一段时间,经过一段时间的考验后,新系统正式替代老系统。对于较复杂的大型系统,
这种方法提供了一个与旧系统运行结果进行比较的机会,
可以对新旧两个系统的时间要求、出错次数和工作效率给以公正的评价。由于与旧系统并行工作,用户消除了尚未认识新系统之前的惊慌与不安。这种方式的主要特点是安全、可靠,但费用和工作量都很大。
3) 分段切换这种切换方式是上面两种方式的结合。在新系统正式运行前,一部分一部分地替代老系统。切换过程中没有正式运行的那一部分,可以在一个模拟环境中进行考验。这种方式既保证了可靠性,又不至于费用太大。但是这种分段切换对系统的设计和实现都有一定的要求,
否则无法实现这种分段切换。
图 6.8是上面三种方式的示意图 。
老系统新系统切换 时间老系统新系统并行 时间老系统新系统分段区间 时间
( b ) 并行切换 ( c ) 分段切换( a ) 直接切换图 6.8 系统切换的三种方式
6.4 系 统 维 护
6.4.1 维护的内容信息系统实施之后,由于各种各样因素的影响,
例如系统运行环境的变化或者程序中存在未检测到的错误等,为了保证系统的正常工作,要求系统不断地完善并能适应各种变化,还需要进行系统的维护工作 。
系统维护的工作内容大致包括:
(1) 软件的维护:运行中发现软件测试阶段未发现的错误,或者用户对系统的功能要求发生变化,以及业务量的急剧增长等都有可能需要对软件进行修改 。
(2) 数据文件及代码的维护:随着系统的变化,原有的数据文件或代码不能适应新的需要,需要维护数据文件或修改旧的代码系统 。
(3) 硬件的维护:包括计算机,网络及相关设备的日常管理和维护工作 。 一旦硬件发生故障,必须有专门的人员进行修理 。
(4) 机构和人员的变动:机构和人员的变动有时也会对信息系统的流程和对设备及程序的维护工作产生影响。
6.4.2 软件维护的分类软件维护是信息系统维护的主要工作,软件工程学科将软件维护定义为,对现有运行软件进行修改而同时保留其主要功能不变的过程,。 通常软件维护工作可分为四类:
1) 改正性维护软件测试不可能将所有潜在的错误都查找出来,设计再好的测试用例也难免存在遗漏。运行中必然会发现软件错误,需要维护人员进行调试并改正错误。这类维护工作称为改正性维护或纠错性维护。
2) 适应性维护计算机系统硬件及操作系统的更新换代频繁,而一个大型的信息系统软件开发常常需要耗费巨资,因为系统运行环境的改变而废弃不用是很不合算的 。 因此要求维护人员对原来的软件进行修改,以适应新的软硬件运行环境的要求 。 这类维护活动称为适应性维护 。
3) 完善性维护当系统投入使用之后,用户会提出增加新功能,修改已有的功能以及一般的改进和建议 。 为了满足和部分满足这类要求,所进行的维护活动称为完善性维护 。 完善性维护占软件维护工作的大部分 。
4) 预防性维护为了给未来的改进奠定更好的基础而修改软件的维护活动称为预防性维护 。 这类维护活动相对较少 。
维护工作的多少和难易程度取决于软件设计的水平,软件开发应该注意按照软件工程方法的要求进行,以提高软件的可维护性 。 软件的可维护性由维护人员理解,改正,改动和改进软件的难易程度来衡量 。 开发过程的每个阶段必须有完备一致的文档资料,在设计软件结构时应注意提高模块之间的独立性 。
完备一致的文档资料有助于维护阶段阅读理解程序,对软件维护之后相应的文档资料也应该进行修改以保持软件与文档的一致性 。 模块之间的独立性可以避免维护工作中对某一个模块的修改而影响到系统中的其它模块 。
完善性维护
5 0 %
改正性维护
2 1 %
适应性维护
2 5 %
其它
4 %
图 6.9 四种维护工作量的分布
6.4.3 维护的管理系统的各项维护工作都应有专人负责,并且通过一定的审批手续 。
系统硬件维护的管理相对简单,本节我们主要讨论软件维护的管理,
因为软件维护相对影响较大,例如一个业务处理过程的修改,往往会影响其它过程或子系统 。
软件维护工作应由相对固定的维护组织来承担,一般应少吸收设计人员参加 。 这样可以促使设计人员在设计时注意提高软件的可维护性,另一方面不会影响设计人员从事新项目的开发工作 。
软件维护首先由系统操作的各类人员或业务管理人员提出对某项工作的要求,申请形式可以是书面报告或填写专门的维护申请表。维护要求被批准后,系统管理员组织维护人员实施维护,软件维护的工作流程可参考图 6.10。
类型估量错误严重程度评价优先级开始分析问题计划修改进度维护任务开始分析复审改正性适应性完善性不严重严重分配人员分配人员开发目录低高错误修改目录维护要求修改后的软件图 6.10 软件维护工作流程维护要求按其类型分成两条不同的处理路线 。 对于适应性和完善性维护来说,其性质与开发工作类似 。
对每次的软件维护活动都应作出维护记录,并存入软件维护数据库中 。 维护记录一般包含下面的一些内容:
● 程序标识;
● 源语句数;
● 使用的程序设计语言;
● 程序安装的日期;
● 自从安装以来程序运行的次数;
● 自从安装以来程序失效的次数;
● 程序改动的层次和标识;
● 因程序修改而增加的源语句数;
● 因程序修改而删除的源语句数;
● 每个改动所耗费的人时数;
● 程序修改的日期;
● 软件维护工程师的姓名;
● 维护要求表的标识;
● 维护类型;
● 维护开始和完成的日期;
● 累计用于维护的人时数;
● 该维护完成所带来的纯效益 。
6.5 实 验 五
6.5.1 实验目的安排本次实验的主要目的为:
① 熟悉单元测试和集成测试的主要任务;
② 掌握白盒测试和黑盒测试设计测试用例的主要方法;
③ 学习编写测试计划和测试报告;
④ 熟悉集成测试的主要步骤;
⑤ 熟练掌握常见开发工具的调试功能的使用方法,积累程序调试的经验。
6.5.2 实验内容对实验四中编写的各个模块的代码分别进行单元测试,排除错误,然后编写集成测试计划,进行集成测试,
最后编写测试报告。
6.5.3 实验步骤本次实验分以下几步:
① 小组内成员交换阅读各自编写的程序代码,对照常见错误表检查是否存在错误;
② 编写各模块的驱动模块和桩模块;
③ 准备各模块的条件组合覆盖或路径覆盖的测试用例;
④ 测试各模块,检查测试结果,排除错误;
⑤ 准备集成测试的测试用例 ( 等价类划分法,边界值分析法 ) ;
⑥ 编写集成测试计划;
⑦ 进行集成测试;
⑧ 编写测试报告。