1、第六章检验和测试方法6.1 检验的基本概念6.2 软件评审6.3 测试的基本概念6.4 白盒法6.5 黑盒法6.6 测试步骤6.7 联合测试6.8 系统测试6.9 测试计划习题六第六章检验和测试方法 大型软件系统的开发经历了需求分析、设计和编程三个阶段,近二十年来,软件工作者提出了许多方法指导人们在分析、设计和编程中改进软件的质量并尽量避免错误的产生,本书前几章已介绍了这些方法。但是,由于分析、设计和编程是由人来完成的,人在工作中难免会犯各种各样的错误,如在相互交流中产生误会,或在表达中有不精确性等,所以尽管采用了先进的方法,软件中的错误仍然在所难免,对于规模大、复杂性高的大型软件系统更是如此
2、。例如本书中的许多实例,虽经编者反复检查,但细心的读者仍会发现其中存在着错误,这是不足为怪的。6.1 检验的基本概念检验的基本概念 第六章检验和测试方法据统计,一个素质较好的程序员,在他交付的程序中,错误率为1,即每100个语句中约含有一个错误;而水平差的程序员,其早期编写的程序中,每个语句就可能含有一个甚至两个错误。所以我们必须接受这样一个事实:软件中存在着错误,这是由人类本身能力的局限性造成的,对此我们不必大惊小怪,或对开发人员、过多地抱怨或责备。第六章检验和测试方法这是问题的一个方面,另一方面是当代计算机逐步应用到国民经济的一些重要领域,如银行管理、经济决策部门的信息收集、空中交通管理或
3、核反应堆控制等,软件系统的任何一个错误,都可能使财产,甚至生命遭到惨重损失,所以人们对软件系统的可靠性提出了很高的要求,这就同前面所述的基本事实构成了一对尖锐的矛盾。面对这对矛盾,人们得出的结论是:伴随着软件的开发,必须在技术上、管理上采取措施对软件进行严格检验,正如有了铅笔就必需有橡皮一样,检验是软件开发过程中不可缺少的部分。检验的目的在于发现其中的错误并及时纠正。检验时应想方设法,力图多发现错误,发现的错误越多就说明检验的收效越大、越成功。第六章检验和测试方法目前软件检验的手段有三类,即动态检查、静态检查和正确性证明。动态检查就是指传统的“测试”,这种方法是使程序有控制地运行,并从多种角度
4、观察程序运行时的行为,以发现其中的错误。“测试”是否能够发现所有的错误呢?回答是“不可能”,下面用例子来说明这一点。测试的关键问题是如何设计测试用例,设计测试用例的方法一般有两类:第六章检验和测试方法 黑盒法。白盒法。如果使用黑盒法,测试人员将程序看成为一个“黑盒”,也就是说,他不关心程序内部是怎么做的,而只是想检查程序是否符合它的“功能说明”。所以使用黑盒法时,测试用例是完全根据程序的功能说明来设计的。第六章检验和测试方法 如果想用黑盒法发现程序中所有的错误,则必须用输入数据的所有可能值来检查程序是否都能产生正确的结果。图6.1是一个很简单的程序,图 6.1它有两个输入变量X、Y,一个输出变
5、量Z。假定程序是在字长为32位的计算机上运行,又假定X、Y都是整数,则输入数据的可能值有 232232264种 如果这个程序执行一次约需一毫秒,那么用所有这些输入数据来测试这个程序将需要五亿年!所以要试遍输入数据是不可能的。第六章检验和测试方法图6.1第六章检验和测试方法 如用白盒法,则需了解程序内部的结构,此时测试用例是根据程序的内部逻辑来设计的。如果想用白盒法发现程序中所有的错误,则至少必须使程序中每种可能的路径都执行一次。图6.2是一个小程序的控制流程图,这个程序由一个循环语句组成,循环次数可达20次,循环体中是一组嵌套的IF语句,其可能的路径有5条,所以从程序的入口A到出口B的路径数就
6、达 520=1014第六章检验和测试方法图6.2第六章检验和测试方法 如果编写一个例子,并用它来测试这个程序共花 次5分钟,则试遍每一条路径要花十亿年!所以同试遍所有的输入数据一样,要试遍所有的路径也是不可能的。使用白盒法时,还应认识到:即使试遍所有的路径,仍不能保证程序符合它的功能要求,因为程序中有些错误是同数据有关的,例如程序错误地将语句X:=Y+Z编写成X:=YZ,但测试中执行该语句时,变量z的值恰好是零,这个错误就不能被发现。另外,程序中还可能遗漏了某些路径。第六章检验和测试方法 上述 讨论的结论是:虽然试遍输入数据的可能值比试遍所有路径更合理些,但是二者都是不可能的,所以无论测试时选
7、用了多少个例子,它们都仅仅是所有可能的例子中极小的一部分,如果执行这些例子的结果是错的,则说明程序中确实存在错误;然而如果执行这些例子的结果是正确的,我们并不能认为程序中就没有错误了,这就是Dijksrta说的:“测试只能证明错误的存在,但不能证明错误不存在”。第六章检验和测试方法 静态检查一般是指人工评审软件文档或程序,借以发现其中的错误。由于被评审的文档或程序不必运行,所以称为是“静态”的。人工评阅的手续虽然比较简单,但事实证明这是一个相当有效的检验手段,相当比例的错误往往是通过评审发现的,评审已成为软件开发过程中一项必不可少的质量保证措施。由于人的评阅能力有限,静态检查显然不可能发现所有
8、的错误。第六章检验和测试方法 静态检查也可以用计算机自动进行,只需开发一些检查程序,使它们能“阅读”软件文档和程序,并发现其中某些类型的错误就可以了。动态检查和静态检查的基本问题在于不可能说明软件中不存在错误,人们所能做到的最好结果只是发现错误,因此自然希望找到某种方法能确切地证明程序是没有错误的,这就出现了程序正确性的研究领域。程序证明最常用的方法是归纳断言法,它对程序提出一组命题,如能用数学方法证明这些命题成立,就可保证程序中不存在错误,即它对所有的输入都会产生预期的正确输出。第六章检验和测试方法 程序证明是一个鼓舞人心的想法,它也许对未来的软件开发会有深远影响,但它也是有问题的,其一是设
9、置命题和证明命题需要大量艰苦的脑力劳动,其间的公式推导是极其冗长的,例如某个433行ALGOL程序,其证明长达46页!人们不禁要怀疑这46页的证明中是否又会有错误呢?其二是究竟什么“错误”,例如1.3节提到的美国woonsocket市计算税率的系统能否算是“正确无误”的呢?总之,正确性证明技术目前还处于它的早期,近期内还不适用于大型软件系统。第六章检验和测试方法测试、评审和证明都是卓有成效的,但其功效也是有限的,任一种技术都不足以保证软件的质量,所以软件检验应该是一种综合性的技术。开发一个软件系统时,这三种技术往往都要予以考虑:例如对系统最关键的核心部分可以采用正确性证明的技术;开发过程中每个
10、阶段都要对交付的文档进行正规的评审;程序完成后还要进行全面的测试(已证明是正确的部分也要进行测试),只有将三种技术结合起来才有希望获得质量较好的软件产品(当然不能奢望获得绝对正确的产品)。第六章检验和测试方法 检验工作应该由另一个独立部门(即不负责该系统开发的部门)来主持,因为检验的目的是发现错误,从心理学的角度来说,大多数开发人员不能有效地检验他们自己设计、编写的软件;此外,如果开发人员对问题已经理解错了,由本人来检验显然不能查出这类错误。通常,系统中各个部件的检验,可在开发人员间交换进行,而整个系统的评审和验收,则应由用户或不参加该系统开发的其他专家来完成。第六章检验和测试方法 必须说明的
11、是:在发现错误之后,“排错”(即找出错误的原因并加以纠正)应由软件的作者来完成。本节的结论是:为了保证软件质量,检验是极其重要的。遗憾的是我们目前尚未掌握理想的检验方法,检验所需开支大、难度高,但其效果却远远不能令人满意,我们能够做到的只是在一定的成本和时间进度限制下,尽可能多地发现一些错误。第六章检验和测试方法因此,在质量保证的两类技术事前预防和事后检验之中,我们只能寄希望于前者,也就是说,软件质量主要是开发时决定的,而不是靠检验来保证的;开发时掉以轻心,指望由检验来发现警错误的侥幸心理是错误的。现在,再回顾一下“先苦后甜的座右铭,读者也许又有了进一步的认识。第六章检验和测试方法6.2.1
12、评审过程评审过程 对软件作静态分析的手段之一是人工阅读文档或程序,从而发现其中的错误,这种技术称为评审(Review)。近年来的实践已证明评审是一种很有效的技术,它综合了技术性和管理性措施,手续并不复杂,难度也不很大,所需开支也不高,但效果甚好,专家们已经公认:正规的评审制度对软件的成功是绝对必要的。6.2 软件评审软件评审第六章检验和测试方法评审的种类很多,包括需求复查、概要设计复查、详细设计复查、程序复查和走查等等,其正规化的程度、方式和参加的人员略有不同。本节就软件生命期中几个主要的评审活动,概括地讨论评审过程和评审条款等问题。按照早期的软件开发模式(图1.2),检验工作是放在程序完成之
13、后进行的,所以,软件错误要到最后的测试阶段才能发现(也可能仍然发现不了)并进行纠正,这往往要对系统作很多的修改才能完成,造成人力、物力上的浪费和进度上的压力。第六章检验和测试方法近年来,为了尽早发现错误尽早纠正,从而达到降低成本、提高质量的目的,人们将评审工作与开发过程结合起来,使评审成为每个阶段之后必经的一道手续,这样的模式可用图6.3来说明。第六章检验和测试方法 图 6.3 第六章检验和测试方法 根据这一模式,需求分析阶段完成后,即对需求说明书进行复查;设计阶段完成后,即对设计文档进行复查;编程后可对程序进行复查或走查。由于设计分为概要设计和详细设计两步,所以其评审也有两次,分别在概要设计
14、或详细设计完成后进行。复查的目的是避免错误传递到下一阶段。由于错误发现得越早就越易修改,而且副作用亦越小,所以开发活动和评审活动并行进行是重要的质量保证措施之一。第六章检验和测试方法需求分析和概要设计阶段所犯的错误是二些比较重大的、整体性的错误,其修改涉及面广,纠正的代价较高,相对地说,编程阶段的错误则比较孤立,修改较易。另一方面,由于需求分析和设计的结果是不可执行的软件文档,其描述方式通常也不是形式化的,所以测试和证明技术均无法使用,只有评审是唯一可以发现错误的手段;而编程的结果是可以运行的程序,此时,测试、证明技术都可用来发现错误。由于上述两方面的原因,需求复查和概要设计复查就特别重要,必
15、须邀请一些资历较高的专家,以较正规的方式,慎重、认真地进行,相比之下,详细设计复查和程序复查则在同事之间相互进行检查就可,其正规化程度亦可略低。第六章检验和测试方法由于评审的目的是发现错误,为了获得较好的效果,评审应由开发人员之外的人来主持,开发人员与评审人员相互独立也是质量保证的重要措施之一,评审人员应在软件开发技术、检验技术方面均受过良好的训练,也应具有较丰富的实际开发经验。需求复查的参加人员可以包括开发部门的负责人、用户(包括各个层次的代表),熟悉这类应用系统的专家和开发软件系统的专家等。概要设计复查的参加人员可以是开发部门的负责人、用户(主要是评审用户手册)、以及开发软件系统的专家等。
16、第六章检验和测试方法详细设计复查和程序复查可在开发部门内部同事之间交换进行。一般认为评审人员不必太多,3至10人均可,可由开发部门负责人担任组长。评审的过程如下:评审组长在评审会举行前1至2周将评审材料(文档或程序)发给评审员,要求各人仔细阅读,评审员阅毕应给评审组长一个书面通知证实已读过所有材料。评审会上先由材料作者用投影仪、幻灯等设备介绍情况,通常在作者向评审员介绍情况时,他就可能边讲边发现材料中的一些错误。作者介绍之后,评审员按照评审条款逐条对材料进行检查,发现其中的错误和不足之处,评审条款将在6.2.2中讨论。第六章检验和测试方法 对评审会进行的情况应有详细的记录,会议结束后,组长应交
17、出一份评审报告,列出发现的错误及对修改工作的具体要求。评审会上应注意以下几点:1)必须强调评审是针对软件文档,而不是软件文档的作者,评审会上的发言除为了修改软件之外决不作他用(如作为编写人员晋升、调资的参考)。排除了这类心理障碍,评审员才能畅所欲言,发挥其经验、学识方面的专长,取得良好的评审效果。第六章检验和测试方法 2)评审会的任务只是发现错误而不是纠正错误,纠正错误一般应由软件作者在会后再进行。3)为了保证效果,评审会不要持续过长,一般认为以12小时为宜。如果系统较大,材料较多,评审可分几次进行。第六章检验和测试方法 程序走查(Code Walk Through)是另一种有效的评审活动。同
18、程序复查一样,它也需要先将材料发给评审人员,然后召集他们参加会议,但在会议上采取的步骤却有所不同,它不是按评审条款逐条检查程序,所以不要求与会者充当“计算机”多与会者需要携带一组典型的测试用例来参加会议,会上由程序作者在纸上或黑板上“运行”每个测试用例,即用这些测试数据沿着程序逻辑走一遍,与会者追踪程序的状态(检查变量的值)。第六章检验和测试方法 当然,这样的“运行”速度是极慢的,所以测试用例必须很简单,走查的关键在于:以人工“运行”作为媒介,通过他启发与会者向程序员提出种种问题,从而发现程序中的错误。实际证明,通过向程序员提出发现的错误比直接由测试用例发现的错误要多。第六章检验和测试方法 6
19、.2.2 评审条款评审条款 评审的目的在于尽量快、尽量多地发现错误,所以一般的做法是将软件中常见的备类错误列成清单,作为评审条款(Checklist),评审会上按照评审条款有针对性地进行检查,就可达到多快好省的目的。评审条款有不同的风格,可以是比较原则性的,也可以比较具体,可视评审员的经验和习惯而定。下面是美国波音计算机服务公司的评审条款:第六章检验和测试方法需求复查条款:1)完整性:系统的所有需求是否都写在需求说明书上了?2)正确性:需求说明书上的每个条目是否均叙述正确?3)精确性:需求说明书上的每个条目是否表达得确切,而且只有一种解释?4)一致性:是否有条目同其他的条目相互冲突?5)可测试
20、性:在系统验收时,是否有界面能够明确地说某个条目满足或不满足?6)可行性:在已知经费、进度和技术条件的限制下,每个条目是否可能实现?7)可追踪性:每个条目在现实的用户环境中都能找到它的根据吗?第六章检验和测试方法8)相关性:每个条目是否确与系统的需求相关?概要设计复查条款:1)可追溯性:设计文档中的每个条目是否都能在需求说明书中找到它的根据?2)现实性:设计方案是否是一个现实的解决办法?3)可维护性:某个部分作修改时是否会牵涉到许多其他部分?4)质量:设计方案是否体现了良好的软件结构应具有的种种特征?第六章检验和测试方法5)界面:系统各部分之间的界面是否明确定义了?6)清晰性:设计文档是否表达
21、得清楚?7)其他方案:是否已考虑过其他的设计方案?为什么最后选择了当前这个方案?可以看出,上面两个评审条款列出了需求分析阶段和概要设计阶段最易犯、最常见的一些错误和不足之处,所以按照评审条款进行评审将会是很有效的。第六章检验和测试方法上面两个评审条款的风格均是较抽象,较原则性的,也有不少公司采用一些很具体的评审条款,如需求评审条款是:1)分层数据流图中的父图和子图是否平衡?2)数据流图中的数据是否守恒?”3)数据流图中出现的数据名在数据词典中是否都已定义了?4)数据词典中各个条目同数据流图是否有冲突?5)每个数据项的值范围是否都确定了?6)每个小说明是否表达得清晰、精确?第六章检验和测试方法概
22、要设计评审条款是:l)是否用了“信息隐蔽”这个原则?2)模块是否具有最大的聚合度?3)模块阃耦合度是否最小飞4)软件结构的形态是否合理?5)输入和输出是否平衡?6)作用范围是否在控制范围之内?7)模块间是否有病态的联系?8)结构图中描述的数据流是否与数据流图相对应?9)设计方案中是否避免了重复功能?第六章检验和测试方法 显然,评审条款只能是一种参考,评审会上应根据具体情况作增删。因篇幅所限,本书不再列出详细设计复查和程序复查的评审条款,读者可参阅参考文献1和6。6.2.3评审的特点评审的特点在实际使用中,人们发现,同测试技术相比,评审有其独特的优点:第六章检验和测试方法 1)早发现错误早纠正,
23、所以降低了开发成本。2)由作者之外的其他人参加,可吸收各家之长,效果较好。3)排错比较容易。测试从迹象断定错误存在(如实际输出与预期输出不符),再根据各种现象分析、判断错误的原因,这是一个极其困难的过程;而评审是直接检查软件文档本身,当发现错误时(如规格说明书中有两条相互冲突),原因也是显然的。第六章检验和测试方法 4)测试需对一个个错误分别进行分析、定位,并纠正;而评审按评审条款检查时,往往可成批地发现错误(如按需求分析评审条款查精确性时,发现规格说明书中有5个条目的叙述带有二义性)成批纠正,所以效率较高。5)测试发现错误时,程序员心理比较紧张,总是急于排错,而不能冷静地考虑修改方案,往往错
24、上加错;而评审安排在系统开发的早期,发现错误后,开发人员一般不紧张,可以较全面地权衡,选择修改方案。第六章检验和测试方法 所以,评审看上去是一种平凡普遍的手续,似乎比较单调、枯燥,但其效果却都是显著的。据统计,在较典型的软件开发项目中,30到70的错误是通过评审发现的。所以,我们可以得到这个结论:正规的评审制度对软件的成功是绝对必要的。当然,对大型系统的大量文档和程序,凭人工进行评审,其效果还是有限的,部分评审活动完全可以由计算机自动完成,第十章将介绍具有这类功能的自动工具。第六章检验和测试方法人们往往有这样一种错觉:程序编写出来以后,研制工作就接近尾声了,但是事实并非如此,本书图1.3说明了
25、研制一个软件系统的大部分工作量是花在程序编写出来之后,即测试和维护阶段,其中测试阶段的工作量约占开发期的一半,测试一个大型程序系统的难度,可能比设计这个系统还要大。.6.3测试的基本概念测试的基本概念第六章检验和测试方法下面先看一个小程序的测试工作。程序TRIANGLE输入三个整数,它们表示一个三角形的三条边长,该程序产生一个结果指出该三角形是等腰三角形、等边三角形还是不等边三角形(见图6.4)。第六章检验和测试方法图6.4第六章检验和测试方法 这个程序是很简短的,有一定经验的读者可能认为测试这个程序非常容易,可以很自信地随手写下一些“测试用的例子”(下面简称“测试用例”、或“例子”),例如:
26、a=3,b=4,c=5 a=5,b=5,c=6 a=6,b=6,c=6 等如果对这些测试用例,程序都能给出正确的结果,那么就认为程序是正确的了。第六章检验和测试方法 下面,请这些读者检查一下,你选用的测试用例是否包括了以下一些情况:1)合理的不等边三角形(输入数据为1、2、3或2、5、10等不能算这一类)。2)合理的等边三角形(输入数据为0、0、0等不能算这一类)。3)合理的等腰三角形(输入数据为2、2、4等不能算这一类)。4)等腰三角形的三种排列次序(如3、3、4;3、4、3和4、3、3等)。第六章检验和测试方法5)三个正数,其中两个之和等于第三个。6)第5种情况的三种排列次序(如1、2、3
27、;1、3、2和3、1、2等)。7)三个正数,其中两个之和小于第三个。8)第7种情况的三种排列次序(如1、2、4;l、4、2和4、1、2等)。9)输入数据含有零值。10)输入数据含有负数。11)输入数据含有非整数值。12)三个数均为零。13)输入数据不是三个数(如只有两个输入数)。第六章检验和测试方法 实际调查说明,即使是较有经验的软件人员,在测试该程序时往往也只考虑到上述情况中的六七种。上述13种情况是在分析了某些程序员编写的TRIANGLE程序之后,根据一些常见的错误列出的,所以它们确实是测试中需要考核的,而不是故意吹毛求疵,此外,还应注意到:即使测试用例中包括了上述1 3种情况,我们仍不能
28、保证经过测试的程序就不再含有其他错误了。第六章检验和测试方法TRIANGLE一例说明了,即使是测试一个很小的程序,它也不是轻而易举的任务,测试工作比我们所预料的要复杂得多。不难想像,如果要测试10000个语句以上的软件系统,例如一个编译程序或银行管理系统,将会是多么困难!什么是“测试”?许多人对它的理解是完全错误的,这也是测试工作做得很差的原因之一,例如有人认为“测试的目的是说明程序能正确地执行它应有的功能”,或者“测试是表明程序中不再含有错误”等。第六章检验和测试方法 事实上,同这些人的理解正好相反,“测试”是假定程序中存在错误(这个假定几乎对所有程序都是合理的),因而想通过执行这个程序来发
29、现尽可能多的错误。所以“测试”的恰当定义应该是“为了发现错误而执行程序”。这一定义为测试阶段指出了一个正确的目标,这将对如何成功地进行测试产生深远的影响:如果测试的目标是说明程序中没有错误,程序员则会向着这个目标靠拢,因而下意识地选用一些不易暴露错误的测试用例。但是,如果我们的目标是证实程序中有错误,程序员就会选用一些更能暴露错误的测试用例。所以这个定义对如何设计测试用例、谁应该参加测试、谁不该参加等一系列问题都有很大的影响。第六章检验和测试方法“测试”是否能够发现所有的错误呢?6.1已指出:“测试只能证明错误的存在,但不能证明错误不存在”。既然“彻底地测试”是不可能的,所以测试阶段要考虑的基
30、本问题就是“经济性”了。我们的策略是:在一定的研制时间、研制经费的限制下,通过执行有限个测试用例,尽可能多发现一些错误。那些只能使程序正确地执行的测试用例是没有什么意义的,执行这些测试用例只是白白浪费时间和金钱而已,而能够发现错误的测试用例才是成功的例子。第六章检验和测试方法 如果将某个测试用例发现的错误看作是它的“产品”,则理想的测试用例应该是“高产”的。显然,随意选择的一组测试用例不可能是高产的,所以测试的关键就成为如何设计高产的测试用例了。下面讨论测试阶段应注意的一些基本原则:1)测试用例应该由以下两部分组成:输入数据。预期的输出结果。第六章检验和测试方法这就是说,在执行程序之前应该对期
31、望的输出有很明确的描述,这样,测试后就可将程序的输出同它仔细地对照检查。如果不事先确定预期的输出,就可能把似乎是正确而实际是错误的结果当成是正确的结果。2)不仅要选用合理的输入数据作为测试用例,还应选用不合理的输入数据作为测试用例。许多人往往只注意前者而忽略了后者。为了提高程序的可靠性,输入数据不合理的各种情况是应该认真检查的,例如测试程序TRlANGLE时,就应选用“a=1,b=2,c=5”等例子,以便证实该程序不会错误地认为这是不等边三角形。第六章检验和测试方法 3)除了检查程序是否做了它应做的工作之处,还应检查程序是否还做了它不应做的事情。例如除了检查工资管理程序是否为每个职工正确地产生
32、一份工资单之外,还应检查它是否还产生了多余的工资单。4)应该长期保留所有的测试用例,直至这个程序系统被废弃不用为止。设计测试用例是很费人工的,如果将用过的测试用例丢弃了,以后一旦需要再测试这个程序(例如因为程序内部作了某些修改)就需要再花很多人工,人们往往懒得再次认真地设计测试用例,因而“再测试”很少像初次测试那样“彻底”。如果程序的修改使得前面已测试过的部分产生了错误,“再测试”往往就不能发现这些错误。第六章检验和测试方法 所以,所有的测试用例应作为软件的一部分长期保存下来,这将为维护工作提供有利的条件。最后,再重复一下本节的一些重要结论:1)测试是为了发现错误而执行某个程序。2)测试不能发
33、现所有的错误。3)测试的关键是设计一组“高产”的测试用例。第六章检验和测试方法 测试是相当困难的,它需要有一定的软件方法来指导,也需要有软件工具来辅助。目前人们对测试阶段的了解或许比对其他阶段更少,这一阶段还有许多问题需要研究和探索,“测试技术”正是软件人员目前热心研究的课题之一。本章着重讨论测试阶段最重要的问题如何设计有效的测试用例6.4和6.5将分别介绍设计测试用例的白盒法和黑盒法,6.6和6.8讨论联合测试和系统测试。这里介绍的方法都有一定程度的试探性,在使用它们时,测试人员的经验和创造能力仍然是非常重要的。第六章检验和测试方法 设计测试用例(Test case)的一类方法是白盒法,它以
34、程序的内部逻辑为基础设计测试,用例,所以又称为逻辑覆盖法。应用白盒法时,手头必须有程序的规格说明以及程序清单。白盒法考虑的是测试用例对程序内部逻辑的覆盖程度,6.1已指出,最彻底的白盒法争是覆盖程序中的每一条路径,但是由于程序中一般含有循环,所以路径的数目极大,要执|行每一条路径是不可能的,所以我们只能希望覆盖的程度尽可能高些。6.4 白白 盒盒 法法第六章检验和测试方法 为了衡量测试的覆盖程度,需要建立一些标准,目前常用的一些覆盖标准从低到高分别是:语句覆盖。判定覆盖。条件覆盖。判定条件覆盖。条件组合覆盖。6.4.1至6.4.5先介绍这些覆盖标准,6.4.6再讨论一下应用白盒法的实例。第六章
35、检验和测试方法6.4.1 语句覆盖语句覆盖程序的某次运行一般并不能执行到其中的每一个语句,因此,如果某语句中含有一个错误,而它在测试中没被执行,这个错误就不可能被发现。为了提高发现错误的可能性,应该在测试时执行程序中的每一个语句。“语句覆盖”是一个比较弱的测试标准,它的含义是:选择足够的测试用例,使得程序中每个语句至少都能被执行一次。第六章检验和测试方法 图6.5是一个被测试的程序,它的源程序是:PROCEDURE M(VAR A,B,X:REAL);BEGIN IF(A1)AND(B=O)THEN X:=XA)IF(A一2)OR(X1)THEN X:=X+1 END.第六章检验和测试方法图6
36、.5第六章检验和测试方法 为使程序中每个语句至少执行一次,只需设计一个能通过路径ace的例子就可以了,例如选择输入数据为:A=2,B=O,X=3就可达到“语句覆盖”标准。从本例可看出,语句覆盖实际上是很弱的,如果第一个条件语句中的.AND错误地编写成OR,上面的测试用例是不能发现这个错误的;又如第二个条件语句中X1误写成X0,这个测试用例也不能暴露它;此外,沿着路径础执行时,x的值应该保持不变,如果这一方面有错误,上述测试数据也不能发现它们。第六章检验和测试方法 6.4.2 判定覆盖判定覆盖 比“语句覆盖”稍强的覆盖标准是“判定覆盖”(或称分支覆盖)。这个标准是:执行足够的测试用例,使和程序中
37、每个判定至少都获得一次“真”值和“假”值,或者说使得程序中的每一个分支至少都通过一次。对图6.5的程序,如果设计两个例子,使它们能通过路径ace和abd,或者通过路径a以和abe,就可达到“判定覆盖”标准,为此,我们可以选择输入数据为:A=3,B=O,x=1(沿路径abd执行);A=2,B=1,x=3(沿路径abe执行)。第六章检验和测试方法 程序中含有判定的语句包括lF-THEN-ELSE、DO-wHILE、REPEAT-uNTIL等,除了双值的判定语句外,还有多值的判定语句,如PASCAL中的CASE语句、FORTRAN中带有三个分支的IF语句等。所以“判定覆盖”更一般的含义是:使得每一个
38、判定获得每一种可能的结果。“判定覆盖比“语句覆盖”严格,因为如果每个分支都执行过了,则每个语句也就执行过了。但是,“判定覆盖”还是很不够的,例如上面两个测试用例未能检查沿着路径捌执行时,X的值是否保持不变。第六章检验和测试方法 6.4.3 条件覆盖条件覆盖 一个判定中往往包含了若干个条件,例如图6.5。的程序中,判定(A1)AND(B=O)包含了两个条件:A1以及B=0,所以可引进一个更强的覆盖标准“条件覆盖”。“条件覆盖”的含义是:执行足够的测试用例,使得判定中的每个条件获得各种可能的结果。图6.5的程序有四个条件:A1、B=0、A=2、X1第六章检验和测试方法为了 达到“条件覆盖”标准,需
39、要执行足够的测试用例使得在a点有:A1、A1、B=0、B0等各种结果出现,以及在6点有:A=2、A2、X1、X1等各种结果出现。我们只需设计以下两个测试用例就可满足这一标准:A=2,B=0,X=4(沿路径ace执行);A=l,B=1,X=1(沿路径abd执行)。第六章检验和测试方法 虽然同样只要两个测试用例,但这两个测试用例比642中的两个更有效了。“条件覆盖”通常比“判定覆盖”强,因为它使一个判定中的每一个条件都取到了两个不同的结果,而判定覆盖则不保证这一点。但是也可能有相反的情况,如对语句 IF(A AND B)THEN S设计两个测试用例,使其满足“条件覆盖”:即使A为“真”并使B为“假
40、”,以及使A为“假”而且B为“真”,但是这两个测试用例都未能使语句S得以执行。第六章检验和测试方法 又如,对图6.5的程序,下面两个例子满足“条件覆盖”,但不满足“判定覆盖”:A=1,B=0,X=3 A=2,B=1,X=1因为它们未能使程序中第一个判定的结果为“真”,也未能使第二个判定的结果为“假”。第六章检验和测试方法6.4.4 判断判断/条件覆盖条件覆盖针对上面的问题引出了另一种覆盖标准“判定/条件覆盖”,它的含义是:执行足够的测试用例,使得判定中每个条件取到各种可能的值,并使每个判定取到各种可能的结果。对图6.5的程序,上一节中的两个例子 A=2,B=O,X=4 A=1,B=1,X=1第
41、六章检验和测试方法是满足这一标准的。“判定条件覆盖”似乎是比较合理的,但事实并非如此,因为大多数计算机不能用一条指令对多个条件作出判定,而必须将源程序中对多个条件的判定分解成几个简单判定,所以较彻底的测试应使每一个简单判定都真正取到各种可能的结果。第六章检验和测试方法 图6.6是由编译系统产生的图6.5的目标程序。上面的两个例子未能使目标程序中的每一个简单判定取到各种可能的结果:它们不能使判定I为“假”也不能使判定K为“真”,其原因在于:含有AND或OR的逻辑表达式中,某些条件将抑制其他条件,例如逻辑表达式A AND B,如果A为“假”,目标程序就不再检查条件B了,这样B中的错误就发现不了。第
42、六章检验和测试方法 上面的讨论说明了,尽管“判定条件覆盖”看起来能使各种条件取到所有可能的值,但实际上并不一定能检查到这样的程度。第六章检验和测试方法图6.6第六章检验和测试方法6.4.5 条件组合覆盖条件组合覆盖 针对上述问题又提出了另一种标准“条件组合覆盖”。它的含义是:执行足够的例子,使得每个判定中条件的各种可能组合都至少出现一次。显然,满足“条件组合覆盖”的测试用例是一定满足“判定覆盖”、“条件覆盖”和“判定条件覆盖”的。第六章检验和测试方法 再看图6.5的程序,我们需要选择适当的例子,使得下面8种条件组合都能够出现:1)A1,B=0 2)A1,B0 3)A1,B=0 4)A1,B0
43、5)A一2,X1 6)A一2,X1 7)A2,Xl 8)A2,x1第六章检验和测试方法 必须注意到,5)、6)、7)、8)四种情况是第二个IF语句的条件组合,而x的值在该语句之前是要经过计算的,所以我们还必须根据程序的逻辑推算出在程序的入口点x的输入值应是什么。下面四个例子可以使上述8种条件组合至少出现一次:A=2,B=0,X=4使1)、5)两种情况出现;A=2,B=1,X=1使2)、6)两种情况出现;A=1,B=0,X=2使3)、7)两种情况出现;A=l,B=1,X=1使4)、8)两种情况出现。第六章检验和测试方法细心的读者会发现,上面四个例子虽然满足条件组合覆盖,但并不能覆盖程序中的每一条
44、路径,例如路径acd就没有执行。注意到该程序一共只有四条路径,就可以看出条件组合覆盖标准仍然是多么不彻底了。第六章检验和测试方法 6.4.6 实例实例工资管理程序工资管理程序 前几节叙述了白盒法的几种常用覆盖标准,应用白盒法的基本步骤如下:(1)按照某种覆盖标准,选择一组需覆盖的路径。(2)确定覆盖上述路径所需的输入数据。(3)计算与输入数据相应的输出。这里每一步都是相当困难的,需要人们做大量艰辛的工作。下面以工资管理程序为例说明白盒法的运用过程。第六章检验和测试方法 工资管理程序BONUS的输入数据是职员表(Employee Table)和部门表(DepartmentTable)(图6.7)
45、。职员表由姓名(Name)、职务(Job Code)、部门(Dept.)和工资(salary)四项组成,部门表由部门(Dept.)和销售量(sales)两项组成。程序的功能是:“为销售量最大的部门中每一个职员增加200元工资,但是,如果某个职员的原有工资已达15000元,或者他的职务是经理,则只给他增加100元,如果程序能正常地完成,则输出出错码0;如果输入表格中没有任何条目,则输出出错码1;如果没有职员在部门表中销售量最大的部门中工作,则输出出错码2”。第六章检验和测试方法 图 6.7第六章检验和测试方法 表6.l是BONUS的源程序,参数表中EMPTAB、DEPTTAB分别是职员表和部门表
46、,ESIZE、DSIZE分别是这两个表的长度,ERRCODE是出错码。为简单起见,这里略去了说明部分和注释。第六章检验和测试方法第六章检验和测试方法 我们相信这个程序中含有错误,所以需要对它进行测试,这里先用白盒法设计测试用例。不管采用哪一种覆盖标准,首先都需列出程序中的判定,所以必须考虑所有的条件句和循环句。本例中只要输入表格不空,循环句总会经历进入循环体和跳过循环体这两种情况(因为循环终值都大于等于循环初值),所以就不必专门考虑了,需要分析的只是表6.2六个条件语句中的判定。一般说来,采用“条件组合覆盖”效果较好,这里为了作出比较,我们依次采用各种覆盖标准(语句覆盖除外,因为它太局限了)。
47、第六章检验和测试方法第六章检验和测试方法为了达到“判定覆盖”标准,我们需要选择足够的测试用例,使得上述6个判定都取到两种结果,这就需要使表6.3列出的1 2种情况出现。第六章检验和测试方法第六章检验和测试方法 图6.8的两个测试用例可以满足这一要求,按照6.1指出的原则,每个测试用例要说明输入数据和期望的输出结果(图中“职务”一栏,“E”表示是一般职员,“M”表示是经理)。第六章检验和测试方法图6.8第六章检验和测试方法 虽然这两个例子满足“判定覆盖”标准,但是它们不能发现程序中许多其他可能的错误,例如没有检查ERRCODE为0、职员是经理、部门表为“空”等情况。如果采用“条件覆盖”标准,则必
48、须使判定中的每一个条件取到两种可能的值,这就要使表6.4列出的l 6种情况出现。第六章检验和测试方法第六章检验和测试方法 这里可以看出一个问题,尽管图6.9的测试用例满足“条件覆盖”标准,但是它们可能比图6.8中满足“判定覆盖”标准的测试用例差,因为它们不能执行每一个语句(如语句 1 9),而且它们起的作用也不比图6.8的测试用例多许多,如未能使ERRCODE0,如果语句2误写成(ESIZE0)AND(DSIZE0),这个错误也不能被发现。第六章检验和测试方法 使用“判定条件覆盖”标准,就可克服图6.9中例子的弱点,我们需要提供足够的测试用例使得所有判定和条件都取到两个不同的值,这里只需使图6
49、.9中的职员JONES为经理,而使LORIN不是经理,则判定l6就可取到两种结果,语句19因而得以执行。但是这样做实际上并不一定比图6.8的测试用例好,如果所用的编译系统将含有“OR”的表达式处理成:遇到第一项为“真”就不再检查后面的项,则这样的两个测试用例并不能检查到JOB(K)=“M”这一部分。第六章检验和测试方法最后我们考虑“条件组合覆盖”标准,它需要足够的例子,使得每个判定中条件的各种组合情况都出现一次。本例中判定6、9、13和21各有两种组合,判定2和16各有4种组合。我们可以先选一个测试用例使其包含尽可能多的组合情况,再选另一测试用例使其包含尽可能多的余下的组合情况,直至得到一组测
50、试用例能包含所有的组合情况。图6.10是满足“条件组合覆盖”标准的一组测试用例,它比前面几组测试用例都全面,这也就说明了,我们在一开始就应采用这个覆盖标准。第六章检验和测试方法图6.10第六章检验和测试方法 极其重要的一点是:即使是满足“条件组合覆盖”标准的例子(图6.10)仍不能发现BONUS中许多其他的错误,例如没有检查ERRCODEO的情况,所以如果语句l被遗漏了就查不出,又如语句l 6中l5000.00误写成15000.01也是发现不了的,或者SALARY(K)15000误写成SALARY(K)15000也是发现不了的;又如果BONUS程序没有对部门表或职员表的最后一行进行处理,这个错