测试策略(1)
软件生命周期测试策略
软件开发与软件测试
软件开发过程是一个自顶向下,逐步细化的过程。首先,在软件计划阶段定义了软件的作用域,然后进行软件需求分析,建立软件的数据域、功能和性能需求、约束及一些有效性准则。接着进入软件开发,进行软件设计,把设计用某种程序设计语言转换成程序代码。而测试过程则是依照相反的顺序安排自底向上,逐步集成的过程。低一级测试为上一级测试准备条件。当然不排除两者平行地进行测试。
下图中所示,首先对每一个程序模块进行单元测试,消除程序模块内部在逻辑上和功能上的错误和缺陷。再对照软件设计进行集成测试,检测和排除子系统结构上的错误。随后再对照需求,进行确认测试。最后从系统整体出发,运行系统,看是否满足要求。
软件测试策略
测试过程按4个步骤进行,即单元测试、集成测试、确认测试和系统测试。
开始是单元测试,集中对用源代码实现的每一个单元进行测试,检查各个程序模块是否正确地实现了规定的功能。然后,把已测试过的模块组装起来,进行集成测试,主要对与设计相关的软件体系结构的构造进行测试。为此,在将一个一个实施了单元测试并确保无误的程序模块组装成软件系统的过程中,对正确性和程序结构等方面进行检查。确认测试则是要检查已实现的软件是否满足了需求规格说明中确定了的各种需求,以及软件配置是否完全、正确。最后是系统测试,把已经经过确认的软件纳入实际运行环境中,与其他系统成分组合在一起进行测试。
1.测试信息流
测试过程需要以下三类输入:
-
软件配置:包括软件需求规格说明、软件设计规格说明、源代码等。
-
测试配置:包括测试计划、测试用例、测试驱动程序等。实际上,在整个软件工程中,测试配置只是软件配置的一个子集。
-
测试工具:为提高软件测试效率,可使用测试工具支持测试工作,其作用就是为测试的实施提供某种服务,以减轻测试任务中的手工劳动。
2.分析设计阶段
分析设计阶段的测试工作是评审与测试相结合的过程,主要包括需求说明书评测、概要设计说明书评测、详细设计说明书评测以及软件编码规范评测等。
(1)需求说明书评测
-
编制良好的需求说明书8条原则
①功能与实现分离,即描述要“做什么”而不是“怎样实现”
②要求使用面向处理的规格说明语言,讨论来自环境的各种刺激可能导致系统做出什么样的功能性反应,来定义一个行为模型,从而得到“做什么”的规格说明。
③如果目标软件只是一个大系统中的一个元素,那么整个大系统也包括在规格说明的描述之中。描述该目标软件与系统的其他元素交互的方式。
④规格说明必须包括系统运行的环境。
⑤系统规格说明必须是一个认识的模型,而不是设计或实现的模型。
⑥规格说明必须是可操作的。规格说明必须是充分完全和形式的,以便能够利用它决定对于任意给定的测试用例,已提出的实现方案是否都能够满足规格说明。
⑦规格说明必须容许不完备性并允许扩充。
⑧规格说明必须局部化和松散的耦合。它所包括的信息必须局部化,这样当信息被修改时,只要修改某个单个的段落。同时,规格说明应被松散地构造,以便能够很容易地加入和删去一些段落。
这些原则对于其他各种形式的规格说明都适用,但要结合实际来应用。
-
需求说明书的框架
需求说明书是分析任务的最终产物,通过建立完整的信息描述、详细的功能和行为描述、性能需求和设计约束的说明、合适的验收标准,给出对目标软件的各种需求。
-
需求说明书评测内容
需求说明书评测作为需求分析阶段工作的复查手段,应该对功能的正确性、完整性和清晰性,以及其他需求给予评测。
①系统定义的目标是否与用户的要求一致
②系统需求分析阶段提供的文档资料是否齐全
③文档中的所有描述是否完整、清晰,准确地反应用户要求
④与所有其他系统成分的重要接口是否都已经描述
⑤被开发项目的数据流与数据结构是否足够、确定
⑥所有图标是否清楚,在不补充说明时能否理解
⑦主要功能是否已包括在规定的软件范围之内,是否都已充分说明
⑧软件的行为和它必须处理的信息、必须完成的功能是否一致
⑨设计的约束条件或限制条件是否符合实际
⑩是否考虑了开发的技术风险
⑪是否考虑过软件需求的其他方案
⑫是否考虑过将来可能会提出的软件需求
⑬是否详细制定了检验标准,它们能否对系统定义是否成功进行确认
⑭有没有遗漏、重复或不一致的地方
⑮用户是否审查了初步的用户手册或原型
⑯项目开发计划中的估算是否受到了影响
根据上述讨论的评测内容,可制定需求说明书评测规范:
填表说明:Y—是,TBD—不确定,N—否,NA—不适用。
(2)概要设计说明书评测
-
设计说明书的框架
在整个设计的过程中,各个时期的设计结果需要经过一系列设计质量的评测,以便及时发现和解决在软件设计中出现的问题,防止把问题遗留到开发的后期阶段,造成后患。
-
概要设计说明书评测的内容
①可追溯性:即分析该软件的系统结构、子系统结构,确定该软件设计是否覆盖了所有已确定的软件需求,软件每一成分是否可追溯到某一项需求。
②接口:即分析软件各部分之间的联系,确认该软件的内容接口与外部接口是否已经明确定义。模块是否满足高内聚合低耦合的要求。模块作用范围是否在其控制范围之内。
③风险:即确认该软件设计在现有技术条件下和预算范围内是否能按时实现。
④实用性:即确认该软件设计对于需求的解决方案是否实用。
⑤技术清晰度:即确认该软件设计是否以一种易于翻译成代码的形式表达。
⑥可维护性:从软件维护的角度出发,确认该软件设计是否考虑了方便未来的维护。
⑦质量:即确认该软件设计是否表现出良好的质量特征。
⑧各种选择方案:看是否考虑过其他方案,比较各种选择方案的标准是什么。
⑨限制:评估对该软件的限制是否现实,是否与需求一致。
⑩其他具体问题:对于文档、可测试性、设计过程等进行评估。
为评测设计是否达到目标,必须建立衡量设计的技术标准:
①设计出来的结构应是分层结构,从而建立软件成分之间的控制。
②设计应当模块化,从逻辑上将软件划分为完成特定功能或子功能的构件。
③设计应当既包含数据抽象,也包含过程抽象。
④设计应当建立具有独立功能特征的模块。
⑤设计应当建立能够降低模块与外部环境之间复杂连接的接口。
⑥设计应当能根据软件需求分析获取的信息,建立可驱动、可重复的方法。
根据上述讨论的评测内容以及评测标准,可建立概要设计说明书评测规范:
填表说明:Y—是,TBD—不确定,N—否,NA—不适用。
(3)详细设计说明书评测
详细设计说明书的评测标准和评测内容与概要设计说明书基本相同。
填表说明:Y—是,TBD—不确定,N—否,NA—不适用。
(4)软件编码规范评测
程序良好的风格表现在源程序文档化、数据说明的方法、语句结构和输入/输出方法这四个方面,软件编码规范评测也是围绕这四个方面展开。
-
源程序文档化
①符号名的命名。符号名即标识符,包括模块名、变量名、常量名、标号名、子程序名、数据去名以及缓冲区名等。这些名字应能反映它所代表的实际东西,应有一定实际意义。
②程序的注释。序言性注释通常置于每个程序模块的开头部分,它应当给出程序的整体说明,对于理解程序本身具有引导作用。功能性注释嵌在源程序体中,用以描述其后的语句或程序段是在做什么工作,伙食执行了下面的语句会怎么样。
③标准的书写格式。
-
数据说明
需注意一下几点:
①数据说明的次序应当规范化。
②说明语句中变量安排有序化。
③使用注释说明复杂数据结构。
-
语句结构
在设计阶段确定了软件的逻辑流结构,但构造单个语句则是编码阶段的任务。语句构造力求简单、直接,不能为了片面追求效率而是语句复杂化。
-
输入和输出
输入和输出信息是与用户的使用直接相关的。输入和输出的方式和格式应当尽可能方便用户的使用。在设计和程序编码时应考虑下列原则:
①对所有的输入数据都要进行检验,识别错误的输入,以保证每个数据的有效性。
②检查输入项的各种重要组合的合理性,必要时报告输入状态信息。
③使输入的步骤和操作尽可能简单,并保持简单的输入格式。
④输入数据时,应允许使用自由格式输入。
⑤应允许缺省值
⑥输入一批数据时,最好使用输入结束标志,而不要由用户指定输入数据数目。
⑦在交互式输入时,要在屏幕上使用提示符,明确是交互输入的请求,指明可使用选择项的种类和取值范围。同时,在数据输入的过程中和输入结束时,也要在屏幕上给出状态信息。
⑧当程序设计语言对输入/输出格式有严格要求时,应保持输入格式与输入语句要求的一致性。
⑨给所有的输出加注释,并设计输出报表格式。
3.开发阶段
(1)单元测试
单元测试有称模块测试,是针对软件设计的最小单位——程序模块,进行正确性检验的测试工作。其目的在于发现各模块内部可能存在的各种差错。单元测试需要从程序的内部结构出发设计测试用例。多个模块可以平行地独立进行单元测试。
-
单元测试的内容
需要在五个方面对所测模块进行检查:
①模块接口测试
在单元测试的开始,应对通过所测模块的数据流进行测试。如果数据不能正确地输入和输出,就谈不上进行其他测试。为此,对模块接口可能需要如下的测试项目:
❶调用所测模块时的输入参数与模块的形式参数在个数、属性、顺序上是否匹配;
❷所测模块调用子模块时,它输入给子模块的参数与子模块中的形式参数在个数、属性、顺序上是否匹配;
❸是否修改了只作输入用的形式参数;
❹输出给标准函数的参数在个数、属性、顺序上是否正确;
❺全局量的定义在各模块中是否一致;限制是否通过形式参数来传送。
当模块通过外部设备进行输入/输出操作时,必须附加如下的测试项目:
❶文件属性是否正确;
❷OPEN语句与CLOSE语句是否正确;
❸规定I/O格式说明与I/O语句是否匹配;
❹缓冲区容量与记录长度是否匹配;
❺在进行读写操作之前是否打开了文件;
❻在结束文件处理时是否关闭了文件;
❼正文书写/输入错误,以及I/O错误是否检查并做了处理。
②局部数据结构测试
模块的局部数据结构是最常见的错误来源,应设计测试用例以检查以下各种错误:
❶不正确或不一致的数据类型说明;
❷使用尚未赋值或尚未初始化的变量;
❸错误的初始值或错误的缺省值;
❹变量名拼写错或书写错;
❺不一致的数据类型。
③路径测试
由于通常不可能做到穷举测试,所以在单元测试期间要选择适当的测试用例,对模块中重要的执行路径进行测试。应当设计测试用例查找由于错误的计算、不正确的比较或不正确的控制流而导致的错误。对基本执行路径和循环进行测试,可以发现大量的路径错误。
常见的不正确计算有:
❶运算的有先次序不正确或误解了运算的优先次序;
❷运算的方式错,即运算的对象彼此在类型上不相容;
❸算法错;
❹初始化不正确;
❺运算精度不够;
❻表达式的符号表示不正确。
常见的比较和控制流错误有:
❶不同数据类型的相互比较;
❷不正确的逻辑运算符或优先次序;
❸因浮点数运算精度问题而造成的两值比较不等;
❹关系表达式中不正确的变量和比较符;
❺“差1”错,即不正确地多循环一次货少循环一次;
❻错误的或不可能的循环终止条件;
❼当遇到发散的迭代时不能终止的循环;
❽不适当地修改了循环变量。
④错误处理测试
比较完善的模块设计要求能预见出错的条件,并设置适当的出错处理,以便在一旦程序出错时,能对出错程序重做安排,保证其逻辑上的正确性。这种出错处理也应当是模块功能的一部分。若出现下列情况之一,则表明模块的错误处理功能包含有错误或缺陷:
❶出错的描述难以理解;
❷出错的描述不足以对错误定位,不足以确定出错的原因;
❸显示的错误与实际的错误不符;
❹对错误条件的处理不正确;
❺在对错误进行处理之前,错误条件已经引起系统的干预。
⑤边界测试
在边界上出现错误是常见的。例如,在一段程序内有一个n次循环,当到达第n次重复时就可能会出错。另外,在取最大值或最小值也容易出错。因此,要特别注意数据流、控制流中刚好等于、大于或小于确定的比较值时出错的可能性。此外如果对模块运行时间有要求的话,还要专门进行关键路径测试,以确定最坏情况下和平均意义下影响模块运行时间的因素。这类信息对进行性能评价是十分有用的。
-
单元测试的步骤
通常单元测试是在编码阶段进行的。在源程序代码编制完成,经过评审和验证,确认没有语法错误之后,就开始进行单元测试的测试用例设计。利用设计文档,设计可以验证程序功能、找出程序错误的多个测试用例。对于每一组输入,应有预期的正确结果。模块并不是一个独立的程序,在考虑测试模块时,同时要考虑它和外界的联系,用一些辅助模块去模拟与所测模块相联系的其他模块。这些辅助模块分为两种:
驱动模块(driver)——相当于所测模块的主程序。它接收测试数据,把这些数据传送给所测模块,最后再输出实测结果。
桩模块(stub)——也叫做存根模块。用以代替所测模块调用的子模块。桩模块可以做少量的数据操作,不需要把子模块所有功能都带进来,但不允许什么事情都不做。所测模块、与它相关的驱动模块及桩模块共同构成了一个“测试环境”,如下图。同时驱动模块和桩模块的编写会给测试带来额外的开销。
模块的内聚程度高,可以简化单元测试过程。如果每一个模块只完成一种功能,则需要的测试用例数据将明显减少,模块中的错误也容易被预测和发现。