1、白盒测试,吴鸿韬 ,白盒测试,白盒测试概念 白盒测试的发展 测试覆盖标准 逻辑驱动测试 基本路径测试,白盒测试概念,白盒测试也称结构测试或逻辑驱动测试,是一种测试用例设计方法,它从程序的控制结构导出测试用例。 白盒测试使用被测单元内部如何工作的信息,允许测试人员对程序内部逻辑结构及有关信息来设计和选择测试用例,对程序的逻辑路径进行测试。基于一个应用代码的内部逻辑知识,测试是基于覆盖全部代码、分支、路径、条件。,白盒测试的主要目的:,保证一个模块中的所有独立路径至少被执行一次; 对所有的逻辑值均需要测试真、假两个分支; 对程序进行边界检查(常见的如数据结构越界检查); 检查内部数据结构以确保其有
2、效性。,白盒测试的发展,白盒测试的发展,“是否评估测试效果”指是否有覆盖率或其它评估测试效果的指标, “是否自动测试”指是否形式化描述测试操作并将它用于再次测试, “是否持续测试”指是否以按持续集成的模式开展测试, “是否调测一体”指是否将测试设计高效的融入产品编码与调试的日常实践之中。,白盒测试的发展,第1代白盒测试 在测试发展初期,测试工具很不成熟,人们通常以单步调试代替测试,或采用assert断言、print 语句等简单方式的组织测试体系,即我们所谓的第1代白盒测试,这一时期的测试是半手工的,没实现自动化,测试效果也严重依赖测试者(或者调试者)的个人能力,缺少统一规范的评判标准。,白盒测
3、试的发展,第1 代白盒测试方法存在严重缺陷,主要有:测试过程难以重用,成功经验无法拷贝,测试结果也难以评估并用于改进,这些对于团队运作是非常致命的,白盒测试的发展,第2代白盒测试,将测试操作改用一种形式化语言(通常称为测试脚本)来表述,脚本可以组合成用例,用例可组合成测试集,用例与测试集再统一到测试工程中管理,把测试脚本保存到文件,重用问题解决了。另外,代码覆盖率功能使测试结果可以评估,能直观的看到哪些代码或分支未被覆盖,然后有针对性的增加测试设计。,白盒测试的发展,目前市面上有大量商用工具,如RTRT、CodeTest、Visual Tester、C+ Tester 等都属于这第2代白盒测试
4、工具。,白盒测试的发展,第2 代白盒测试解决了重复测试问题,但没解决持续测试问题。简单来说,重复测试使测试操作能以规范格式记录,当被测对象没变化(或变化很少)时,测试用例是可重用的,但如果源码大幅调整(甚至重构),或者按迭代模式不停追加新功能时,如何维持用例同步增长,并与源码一起同步更新,已经不是简单的增强用例复用能力就能解决的。因为代码更新与用例更新交织进行,测试用例与被测源码一样对等的成为日常工作对象,必然促使原有工作模式与测试方法产生变革,概括而言,白盒测试过程要从一次测试模式过渡到持续测试模式。,白盒测试的发展,某通信产品在V1版本编码完成时,进行过规范的单元测试活动,之后V2、V3要
5、不断增加功能、修改功能,就放弃单元测试了,当V3最后市场交付时统计发现,相对V1版本,代码修改量已达到40%。QA 从其中两个模块随机抽取100 个问题单做缺陷分析,结果发现:第一个模块有50%的问题是在V1版本单元测试结束后引入的,而另一模块也有30%问题是单元测试后引入的。,白盒测试的发展,第3 代白盒测试工具以xUnit 为代表,包括JUnit、DUnit、CppUnit 等 区别第2 代方法与第3 代方法,主要是测试理念上差别,白盒测试的发展,第4 代白盒测试尝试解决软件测试的深层次矛盾:测试的投入产出比问题。,白盒测试的发展,研发资源总是有限的,你可以把测试人员与开发人员的比例配到1
6、:1,也可以配到2:1,甚至5:1,但你做不到10:1、100:1, 如果你有钱,也有人,完全可以按100:1或更高比例配置,这时所有测试瓶颈都没了,你可以让测试人员边喝咖啡边干活,因为每新写1行代码总有人编出100行脚本测试它,还怕产品不稳定吗?,白盒测试的发展,第4 代白盒测试方法相对第3代方法,增加了将测试过程(包括测试设计、执行与改进)高效的融入开发全过程,4GWM在3个关键领域的9项关键特征,A. 第一关键域:在线测试 1、 在线测试驱动 2、 在线脚本桩 3、 在线测试用例设计、运行,及评估改进,4GWM在3个关键领域的9 项关键特征,B. 第二关键域:灰盒调测 4、 基于调用接口
7、 5、 调试即测试 6、 集编码、调试、测试于一体,4GWM在3个关键领域的9项关键特征,C. 第三关键域:持续测试 7、 测试设计先行 8、 持续保障信心 9、 重构测试设计,参考资料,wayne chan,第4代白盒测试方法介绍理论篇 http:/ http:/ 领测科技 VcSmith&VcTester,白盒测试的发展,所谓在线测试,是指被测程序启动后,用例在线设计、调试、运行,运行结果在线查看的测试方法。因为所有测试操作都在线进行,测试用例不必编译链接,被测程序也不用复位重起,被测环境(被测系统的变量、函数等属性)在线可查看,所以该测试模式非常高效,另外,各测试步骤所见即所得,人性化的
8、操作过程很容易被广大开发人员接受。脚本语言具有在线更新功能,比如定义一个脚本函数,调用一次后,发现某个地方处理不对,于是重写这个函数,然后在线的更新这个函数定义。,测试覆盖标准,白盒法特点:以程序的内部逻辑为基础设计测试用例,所以又称为逻辑覆盖法。应用白盒法时,手头必须有程序的规格说明以及程序清单。 白盒法考虑的是测试用例对程序内部逻辑的覆盖程度。,测试覆盖标准,测试覆盖标准,流程图中包括了一个执行达20次的循环。那么它所包含的不同执行路径数高达520条,若要对它进行穷举测试,覆盖所有的路径。假使测试程序对每一条路径进行测试需要1毫秒,同样假定一天工作24小时,一年工作365 天, 那么要想把
9、如图所示的小程序的所有路径测试完,则需要3170年。,测试覆盖标准,语句覆盖:是一个比较弱的测试标准,它的含义是:选择足够的测试用例,使得程序中每个语句至少都能被执行一次。 它是最弱的逻辑覆盖,效果有限,必须与其它方法交互使用。,测试覆盖标准,判定覆盖(也称为分支覆盖):执行足够的测试用例,使得程序中的每一个分支至少都通过一次。 判定覆盖只比语句覆盖稍强一些,但实际效果表明,只是判定覆盖,还不能保证一定能查出在判断的条件中存在的错误。因此,还需要更强的逻辑覆盖准则去检验判断内部条件。,条件覆盖,条件覆盖:执行足够的测试用例,使程序中每个判断的每个条件的每个可能取值至少执行一次; 条件覆盖深入到
10、判定中的每个条件但可能不能满足判定覆盖的要求。,测试覆盖标准,判定/条件覆盖:执行足够的测试用例,使得判定中每个条件取到各种可能的值,并使每个判定取到各种可能的结果。 判定/条件覆盖有缺陷。从表面上来看,它测试了所有条件的取值。但是事实并非如此。往往某些条件掩盖了另一些条件。会遗漏某些条件取值错误的情况。为彻底地检查所有条件的取值,需要将判定语句中给出的复合条件表达式进行分解,形成由多个基本判定嵌套的流程图。这样就可以有效地检查所有的条件是否正确了。,测试覆盖标准,条件组合覆盖:执行足够的例子,使得每个判定中条件的各种可能组合都至少出现一次。 这是一种相当强的覆盖准则,可以有效地检查各种可能的
11、条件取值的组合是否正确。它不但可覆盖所有条件的可能取值的组合,还可覆盖所有判断的可取分支,但可能有的路径会遗漏掉。测试还不完全。,白盒测试的主要方法,逻辑驱动测试语句覆盖判定覆盖条件覆盖判定/条件覆盖条件组合覆盖 基本路径测试,逻辑驱动测试,语句覆盖:语句覆盖就是设计若干个测试用例,运行被测试程序,使得每一条可执行语句至少执行一次 判定覆盖(也称为分支覆盖):设计若干个测试用例,运行所测程序,使程序中每个判断的取真分支和取假分支至少执行一次; 条件覆盖:设计足够多的测试用例,运行所测程序,使程序中每个判断的每个条件的每个可能取值至少执行一次;,逻辑驱动测试,判定/条件覆盖:设计足够多的测试用例
12、,运行所测程序,使程序中每个判断的每个条件的所有可能取值至少执行一次,并且每个可能的判断结果也至少执行一次,换句话说,即是要求各个判断的所有可能的条件取值组合至少执行一次; 条件组合覆盖:设计足够多的测试用例,运行所测程序,使程序中每个判断的所有可能的条件取值组合至少执行一次;,基本路径测试,设计足够多的测试用例,运行所测程序,要覆盖程序中所有可能的路径。这是最强的覆盖准则。但在路径数目很大时,真正做到完全覆盖是很困难的,必须把覆盖路径数目压缩到一定限度。 在程序控制流程的基础上,分析控制构造的环路复杂性,导出基本可执行路径集合,从而设计测试用例,语句覆盖,语句覆盖”是一个比较弱的测试标准,它
13、的含义是:选择足够的测试用例,使得程序中每个语句至少都能被执行一次。 float M (float A,float B,float X) if (A1) ,语句覆盖,为使程序中每个语句至少执行一次,只需设计一个能通过路径ace的例子就可以了,例如选择输入数据为: A=2,B=0,X=3 就可达到“语句覆盖”标准。,语句覆盖,语句覆盖,从上例可看出,语句覆盖实际上是很弱的,如果第一个条件语句中的AND错误地编写成OR,上面的测试用例是不能发现这个错误的;又如第三个条件语句中X1误写成X0,这个测试用例也不能暴露它,此外,沿着路径abd执行时,X的值应该保持不变,如果这一方面有错误,上述测试数据也
14、不能发现它们。,语句覆盖,void DoWork(int x,int y,int z) int k=0,j=0;if(x3) /语句块3,语句覆盖,为了测试语句覆盖率只要设计一个测试用例就可以把三个执行语句块中的语句覆盖了。测试用例输入为:x=4、y=5、z=5程序执行的路径是:abd,语句覆盖,该测试用例虽然覆盖了可执行语句,但并不能检查判断逻辑是否有问题,例如在第一个判断中把&错误的写成了|,则上面的测试用例仍可以覆盖所有的执行语句。 一般认为“语句覆盖”是很不充分的一种标准,是最弱的逻辑覆盖准则。,判定覆盖,执行足够的测试用例,使得程序中的每一个判定取真分支和取假分支至少都通过一次。,判
15、定覆盖,对例1的程序,如果设计两个例子,使它们能通过路径ace和abd,或者通过路径acd和abe,就可达到“判定覆盖”标准,为此,可以选择输入数据为: A=3,B=0,X=1 (沿路径acd执行); A=2,B=1,X=3(沿路径abe执行),判定覆盖,判定覆盖,判定覆盖,A=3,B=0,X=1 (沿路径acd执行) A=2,B=1,X=3 (沿路径abe执行),判定覆盖,对于例2的程序,如果设计两个测试用例则可以满足条件覆盖的要求。测试用例的输入为:x=4、y=5、z=5x=2、y=5、z=5上面的两个测试用例虽然能够满足条件覆盖的要求,但是也不能对判断条件进行检查,例如把第二个条件y5错
16、误的写成y5,、上面的测试用例同样满足了判定覆盖。,判定覆盖,往往大部分的判定语句是由多个逻辑条件组合而成,若仅仅判断其整个最终结果,而忽略每个条件的取值情况,比然会遗漏部分测试路径,条件覆盖,“条件覆盖”的含义是:执行足够的测试用例,使得判定中的每个条件的可能取值至少满足一次。,条件覆盖,例1的程序有四个条件: A1、 B=0、A=2、X1 为了达到“条件覆盖”标准,需要执行足够的测试用例使得在a点有: A1、A1、B=0、B0 等各种结果出现,以及在b点有: A=2、A2、X1、X1 等各种结果出现。 现在只需设计以下两个测试用例就可满足这一标准: A=2,B=0,X=4 (沿路径ace执
17、行); A=1,B=1,X=1 (沿路径abd执行)。,条件覆盖,条件覆盖,条件覆盖,A=2,B=0,X=4 (沿路径ace执行) A=1,B=1,X=1 (沿路径abd执行),条件覆盖,对例2中的所有条件取值加以标记。 对于第一个判断: 条件x3 取真值为T1,取假值为F1 条件z5 取真值为T4,取假值为F4,条件覆盖,则可以设计测试用例如下,上面的测试用例不但覆盖了所有分支的真假两个分支,而且覆盖了判断中的所有条件的可能值。,条件覆盖,“条件覆盖”通常比“判定覆盖”强,因为它使一个判定中的每一个条件都取到了两个不同的结果,而判定覆盖则不保证这一点。 “条件覆盖”并不包含“判定覆盖”,如对
18、语句IF(A AND B)THEN S 设计测试用例使其满足“条件覆盖“,即使A为真并使B为假,以及使A为假而且B为真,但是它们都未能使语句S得以执行。,条件覆盖,如对例2设计了下面的测试用例,则虽然满足了条件覆盖,但只覆盖了第一个条件的取假分支和第二个条件的取真分支,不满足分支覆盖的要求。,判定/条件覆盖,判定条件覆盖”,它的含义是:执行足够的测试用例,使得分支中每个条件取到各种可能的值,并使每个分支取到各种可能的结果。 对例1的程序,前面的两个例子 A=2,B=0,X=4 (沿ace路) A=1,B=1,X=1 (沿abd路径) 是满足这一标准的。,判定/条件覆盖,对例2,根据定义只需设计
19、以下两个测试用例便可以覆盖8个条件值以及4个判断分支。,判定/条件覆盖,分支/条件覆盖从表面来看,它测试了所有条件的取值,但是实际上某些条件掩盖了另一些条件。 例如对于条件表达式(x3)&(z3)为假则一般的编译器不在判断是否z5)来说,若x=4测试结果为真,就认为表达式的结果为真,这时不再检查(y5)条件了。因此,采用分支/条件覆盖,逻辑表达式中的错误不一定能够查出来了。,条件组合覆盖,它的含义是:执行足够的例子,使得每个判定中条件的各种可能组合都至少出现一次。显然,满足“条件组合覆盖”的测试用例是一定满足“分支覆盖”、“条件覆盖”和“分支/条件覆盖”的。,条件组合覆盖,再看例1的程序,我们
20、需要选择适当的例子,使得下面 8种条件组合都能够出现: 1)A1, B=0 2) A1, B0 3) A1, B=0 4) A1, B0 5) A=2, X1 6) A=2,X1 7) A2, X1 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)、
21、7)两种情况出现; A=1,B=1,X=1 使 4)、8)两种情况出现。,条件组合覆盖,上面四个例子虽然满足条件组合覆盖,但并不能覆盖程序中的每一条路径,例如路径acd就没有执行,因此,条件组合覆盖标准仍然是不彻底。,条件组合覆盖,1 x3,z3,z=10记做T1 F2,第一个判断的取假分支 3 x=10记做F1 F2,第一个判断的取假分支 5 x=4,y5 记做T3 T4,第二个判断的取真分支 6 x=4,y5 记做F3 T4,第二个判断的取真分支 8 x!=4,y=5记做F3 F4,第二个判断的取假分支,根据定义取4个测试用例,就可以覆盖上面8种条件取值的组合。 测试用例如下表:,上面的测
22、试用例覆盖了所有条件的可能取值的组合,覆盖了所有判断的可取分支,但是却丢失了一条路径abe。,条件组合覆盖,路径测试,路径测试就是设计足够多的测试用例,覆盖被测试对象中的所有可能路径。,路径测试,对于例2,下面的测试用例则可对程序进行全部的路径覆盖。,测试覆盖标准,测试覆盖标准,流程图中包括了一个执行达20次的循环。那么它所包含的不同执行路径数高达520条,若要对它进行穷举测试,覆盖所有的路径。假使测试程序对每一条路径进行测试需要1毫秒,同样假定一天工作24小时,一年工作365 天, 那么要想把如图所示的小程序的所有路径测试完,则需要3170年。,基本路径测试,基本路径测试就是在程序控制图的基
23、础上,通过分析控制构造的环行复杂性,导出基本可执行路径集合,从而设计测试用例的方法。设计出的测试用例要保证在测试中程序的每一个可执行语句至少执行一次。,基本路径测试,前提条件测试进入的前提条件是在测试人员已经对被测试对象有了一定的了解,基本上明确了被测试软件的逻辑结构。 测试过程过程是通过针对程序逻辑结构设计和加载测试用例,驱动程序执行,以对程序路径进行测试。测试结果是分析实际的测试结果与预期的结果是否一致。,基本路径测试,在程序控制流图的基础上,通过分析控制构造的环路复杂性,导出基本可执行路径集合,从而设计测试用例。包括以下4个步骤和一个工具方法: 程序的控制流图:描述程序控制流的一种图示方
24、法。 程序环路复杂度:McCabe复杂性度量。从程序的环路复杂性可导出程序基本路径集合中的独立路径条数,这是确定程序中每个可执行语句至少执行一次所必须的测试用例数目的上界。 导出测试用例:根据环路复杂度和程序结构设计用例数据输入和预期结果。 准备测试用例:确保基本路径集中的每一条路径的执行。,基本路径测试,工具方法:图形矩阵:是在基本路径测试中起辅助作用的软件工具,利用它可以实现自动地确定一个基本路径集。,控制流图的符号,流图是对待测试程序过程处理的一种表示。流图使用下面的符号描述逻辑控制流,每一种结构化构成元素有一个相应的流图符号。,控制流图,流图只有二种图形符号 图中的每一个圆称为流图的结
25、点,代表一条或多条语句。 流图中的箭头称为边或连接,代表控制流。 任何过程设计都要被翻译成控制流图。,控制流图,在将程序流程图简化成控制流图时,应注意: 在选择或多分支结构中,分支的汇聚处应有一个汇聚结点。 边和结点圈定的区域叫做区域,当对区域计数时,图形外的区域也应记为一个区域。,控制流图,控制流图,如果判断中的条件表达式是由一个或多个逻辑运算符 (OR, AND, NAND, NOR) 连接的复合条件表达式,则需要改为一系列只有单条件的嵌套的判断。 例如:1 if a or b2 x3 else4 y 对应的逻辑为:,独立路径,独立路径:至少沿一条新的边移动的路径,1,7,6,2,3,8,
26、9,10,11,4,5,路径1:1-11 路径2:1-2-3-4-5-10-1-11 路径3:1-2-3-6-8-9-10-1-11 路径4:1-2-3-6-7-9-10-1-11,对以上路径的遍历,就是至少一次地执行了程序中的所有语句。,基本路径测试,第一步:画出控制流图流程图用来描述程序控制结构。可将流程图映射到一个相应的流图(假设流程图的菱形决定框中不包含复合条件)。在流图中,每一个圆,称为流图的结点,代表一个或多个语句。一个处理方框序列和一个菱形决测框可被映射为一个结点,流图中的箭头,称为边或连接,代表控制流,类似于流程图中的箭头。一条边必须终止于一个结点,即使该结点并不代表任何语句(
27、例如:if-else-then结构)。由边和结点限定的范围称为区域。计算区域时应包括图外部的范围。,基本路径测试,例4:有下面的C函数,用基本路径测试法进行测试void Sort(int iRecordNum,int iType) int x=0;int y=0;while (iRecordNum- 0)if(0= =iType) x=y+2; break;elseif (1= =iType)x=y+10;elsex=y+20;,基本路径测试,基本路径测试,画出其程序流程图和对应的控制流图如下,基本路径测试 - 计算圈复杂度,第二步:计算环路复杂度环路复杂度是一种为程序逻辑复杂性提供定量测度的
28、软件度量,将该度量用于计算程序的基本的独立路径数目,为确保所有语句至少执行一次的测试数量的上界。独立路径必须包含一条在定义之前不曾用到的边。 有以下三种方法计算环路复杂度: 流图中区域的数量对应于环型的复杂性; 给定流图G的环路复杂度V(G),定义为V(G)=E-N+2,E是流图中边的数量,N是流图中结点的数量; 给定流图G的环路复杂度V(G),定义为V(G)=P+1,P是流图G中判定结点的数量。,基本路径测试 - 计算环路复杂度,对应上面图中的环路复杂度,计算如下: 流图中有四个区域; V(G)=10条边-8结点+2=4; V(G)=3个判定结点+1=4。,基本路径测试 - 导出测试用例,第
29、三步:导出测试用例 根据上面的计算方法,可得出四个独立的路径。(一条独立路径是指,和其他的独立路径相比,至少引入一个新处理语句或一个新判断的程序通路。V(G)值正好等于该程序的独立路径的条数。) 路径1:4-14 路径2:4-6-7-14 路径3:4-6-8-10-13-4-14 路径4:4-6-8-11-13-4-14根据上面的独立路径,去设计输入数据,使程序分别执行到上面四条路径。,基本路径测试 - 准备测试用例,第四步:准备测试用例为了确保基本路径集中的每一条路径的执行,根据判断结点给出的条件,选择适当的数据以保证某一条路径可以被测试到,满足上面例子基本路径集的测试用例是:,基本路径测试
30、 - 准备测试用例,路径1:4-14 输入数据:iRecordNum0,或者取iRecordNum0的某一个值 预期结果:x0 路径2:4-6-7-14 输入数据:iRecordNum1,iType0 预期结果:x2 路径3:4-6-8-10-13-4-14 输入数据:iRecordNum1,iType1 预期结果:x10 路径4:4-6-8-11-13-4-14 输入数据:iRecordNum1,iType2 预期结果:x20,void Sort(int iRecordNum,int iType) int x=0;int y=0;while (iRecordNum- 0)if(0= =iTy
31、pe)x=y+2; break;elseif(1= =iType)x=y+10;elsex=y+20;,基本路径测试,必须注意,一些独立的路径,往往不是完全孤立的,有时它是程序正常的控制流的一部分,这时,这些路径的测试可以是另一条路径测试的一部分。,工具方法:图形矩阵,导出控制流图和决定基本测试路径的过程均需要机械化,为了开发辅助基本路径测试的软件工具,称为图形矩阵(graph matrix)的数据结构很有用。 利用图形矩阵可以实现自动地确定一个基本路径集。一个图形矩阵是一个方阵,其行/列数控制流图中的结点数,每行和每列依次对应到一个被标识的结点,矩阵元素对应到结点间的连接(即边)。在图中,控
32、制流图的每一个结点都用数字加以标识,每一条边都用字母加以标识。如果在控制流图中第i个结点到第j个结点有一个名为x的边相连接,则在对应的图形矩阵中第i行/第j列有一个非空的元素x。,工具方法:图形矩阵,对每个矩阵项加入连接权值(link weight),图矩阵就可以用于在测试中评估程序的控制结构,连接权值为控制流提供了另外的信息。最简单情况下,连接权值是 1(存在连接)或0(不存在连接),但是,连接权值可以赋予更有趣的属性: 执行连接(边)的概率。 穿越连接的处理时间。 穿越连接时所需的内存。 穿越连接时所需的资源。,工具方法:图形矩阵,根据上面的方法对例4画出图形矩阵如下:,工具方法:图形矩阵
33、,连接权为“1”表示存在一个连接,在图中如果一行有两个或更多的元素“1”,则这行所代表的结点一定是一个判定结点,通过连接矩阵中有两个以上(包括两个)元素为“1”的个数,就可以得到确定该图圈复杂度的另一种算法。,基本路径测试再举例,例5:下例程序流程图描述了最多输入50个值(以1作为输入结束标志),计算其中有效的学生分数的个数、总分数和平均值。,步骤1:导出过程的流图。,步骤2:确定环形复杂性度量V(G): 1)V(G)= 6 (个区域) 2)V(G)=EN+2=1612+2=6 其中E为流图中的边数,N为结点数; 3)V(G)=P+1=5+1=6其中P为谓词结点的个数。在流图中,结点2、3、5
34、、6、9是谓词结点。,基本路径测试再举例,基本路径测试再举例,步骤3:确定基本路径集合(即独立路径集合)。于是可确定6条独立的路径: 路径1:1-2-9-10-12 路径2:1-2-9-11-12 路径3:1-2-3-9-10-12 路径4:1-2-3-4-5-8-2 路径5:1-2-3-4-5-6-8-2 路径6:1-2-3-4-5-6-7-8-2,基本路径测试再举例,步骤4:为每一条独立路径各设计一组测试用例,以便强迫程序沿着该路径至少执行一次。 1)路径1(1-2-9-10-12)的测试用例:scorek=有效分数值,当k i ;scorei=1, 2i50;期望结果:根据输入的有效分数
35、算出正确的分数个数n1、总分sum和平均分average。,基本路径测试再举例,2)路径2(1-2-9-11-12)的测试用例:score 1 = 1 ;期望的结果:average = 1 ,其他量保持初值。3)路径3(1-2-3-9-10-12)的测试用例:输入多于50个有效分数,即试图处理51个分数,要求前51个为有效分数;期望结果:n1=50、且算出正确的总分和平均分。,基本路径测试再举例,4)路径4(1-2-3-4-5-8-2)的测试用例:scorei=有效分数,当i100, k i ;期望结果:根据输入的有效分数算出正确的分数个数n1、总分sum和平均分average。,基本路径测试
36、再举例,6)路径6(1-2-3-4-5-6-7-8-2)的测试用例:scorei=有效分数, 当i50;期望结果:根据输入的有效分数算出正确的分数个数n1、总分sum和平均分average。,作业,为以下流程图所示的程序段设计一组测试用例,要求分别满足语句覆盖、判定覆盖、条件覆盖、判定/条件覆盖、组合覆盖和路径覆盖。,作业,根据左图给出的程序流程图,完成以下要求: (1)画出相应的控制流图。 (2)计算环形复杂度。 (3)给出相应的图矩阵。 (4)找出程序的独立路径集合。,控制结构测试的变种,前面所述的基本路径测试技术是控制结构测试技术之一。尽管基本路径测试简单高效,但是,其本身并不充分。下面
37、讨论控制结构测试的其他变种,这些测试覆盖并提高了白盒测试的质量。 条件测试 数据流测试 循环测试。 推荐参考资料 Roger S. Pressman,软件工程-实践者的研究方法,循环测试,循环测试是一种白盒测试技术,注重于循环构造的有效性。 有四种循环:简单循环,串接(连锁)循环,嵌套循环和不规则循环。,循环测试,循环测试 - 简单循环,对于简单循环,测试应包括以下几种,其中的n表示循环允许的最大次数。(1) 零次循环:从循环入口直接跳到循环出口。(2) 一次循环:查找循环初始值方面的错误。(3) 二次循环:检查在多次循环时才能暴露的错误。(4) m次循环:此时的mn,也是检查在多次循环时才能
38、暴露的错误。(5) n(最大)次数循环、n+1(比最大次数多一)次的循环、n-1(比最大次数少一)次的循环。,循环测试 - 嵌套循环,对于嵌套循环,不能将简单循环的测试方法简单地扩大到嵌套循环,因为可能的测试数目将随嵌套层次的增加呈几何倍数增长。这可能导致一个天文数字的测试数目。下面是一种有助于减少测试数目的测试方法。 从最内层循环开始,设置所有其他层的循环为最小值; 对最内层循环做简单循环的全部测试。测试时保持所有外层循环的循环变量为最小值。另外,对越界值和非法值做类似的测试。 逐步外推,对其外面一层循环进行测试。测试时保持所有外层循环的循环变量取最小值,所有其它嵌套内层循环的循环变量取“典
39、型”值。 反复进行,直到所有各层循环测试完毕。 对全部各层循环同时取最小循环次数,或者同时取最大循环次数。对于后一种测试,由于测试量太大,需人为指定最大循环次数。,循环测试 - 串接循环,对于串接循环,要区别两种情况。 如果各个循环互相独立,则串接循环可以用与简单循环相同的方法进行测试。 如果有两个循环处于串接状态,而前一个循环的循环变量的值是后一个循环的初值。则这几个循环不是互相独立的,则需要使用测试嵌套循环的办法来处理。,循环测试 - 非结构循环,对于非结构循环,不能测试,应重新设计循环结构,使之成为其它循环方式,然后再进行测试。,测试用例自动生成,model-driven的测试,可以从从
40、UML-diagram自动生成test case,其中最成熟的是从state diagram生成 基于形式化语言的测试用例自动生成 面向路径的测试数据生成方法,基于形式化语言的测试用例自动生成,在测试用例自动生成方面,Tsai等提出了从关系代数查询表示的规格说明中自动生成测试用例的方法,Weyuker等提出了基于布尔规格说明的测试数据自动生成方法。此外,基于Z语言的测试用例生成技术也己经非常成熟。但这些测试用例生成方法,因为形式化程度太高而难于得到广泛的应用。,面向路径的测试数据生成方法,面向路径的测试数据生成方法,首先确定一条经过给定语句的程序路径,然后在输入域中寻找输入数据,使得在此输入之
41、下,程序执行沿该路径进行,从而使得给定语句被执行。面向路径的测试数据生成又分为符号执行和实际程序执行两类。遗传算法,贪婪算法,总结:,“白盒”法全面了解程序内部逻辑结构、对所有逻辑路径进行测试。“白盒”法是穷举路径测试。在使用这一方案时,测试者必须检查程序的内部结构,从检查程序的逻辑着手,得出测试数据。贯穿程序的独立路径数是天文数字。但即使每条路径都测试了仍然可能有错误。 第一、穷举路径测试决不能查出程序违反了设计规范,即程序本身是个错误的程序; 第二、穷举路径测试不可能查出程序中因遗漏路径而出错。 第三、穷举路径测试可能发现不了一些与数据相关的错误。,控制结构测试,路径测试,利用流图表示控制
42、逻辑 根据流图标识独立路径 确定覆盖测试路径上界的计算(环复杂度计算) 用基本路径法导出测试案例的步骤,条件测试,数据流测试,循环测试,分支测试:真假分支必须至少执行一次的路径策略 域测试:对于大于、小于和等于值的测试路径策略,由变量的定义到变量的使用,构成DU链,覆盖每个DU链至少一次。用此方法为包含循环和嵌套语句的程序选择测试路径的策略,对于简单循环、嵌套循环、串接循环和无结构循环的路径选择策略,白盒测试工具:,内存资源泄漏检查:Numega中的bouncechecker,Rational的Purify等; 代码覆盖率检查:Numega中的truecoverage,Rational的Pur
43、ecoverage,Telelogic公司的logiscope,Macabe公司的Macabe等; 开源覆盖率测试软件gCov等。,Parasoft白盒测试工具集 Jtest Java 代码分析和动态类、组件测试 Jcontract Java 实时性能监控以及分析优化 C+ Test C,C+ 代码分析和动态测试 CodeWizard C,C+ 代码静态分析 Insure+ C,C+ 实时性能监控以及分析优化,.test .Net 代码分析和动态测试 logiscope c/c+ Verlog公司的静态、动态分析工具 还有testbed、Cantata c/c+等 Rational工具集中的p
44、uricoverage和purify、quantify,Compuware白盒测试工具集 BoundsChecker C+,Delphi API和OLE错误检查、指针和泄露错误检查、内存错误检查 TrueTime C+,Java,Visual Basic 代码运行效率检查、组件性能的分析 FailSafe Visual Basic 自动错误处理和恢复系统 Jcheck M$ Visual J+ 图形化的纯种和事件分析工具 TrueCoverage C+,Java,Visual Basic 函数调用次数、所占比率统计以及稳定性跟踪 SmartCheck Visual Basic 函数调用次数、所
45、占比率统计以及稳定性跟踪 CodeReview Visual Basic 自动源代码分析工具,测试用例,IEEE 829标准 编写用于输入的实际数值和预期输出结果数值,测试用例还明确指出使用具体测试用例产生的测试程序的任何限制,白盒测试的发展,设计测试用例,先通过脚本构造被测函数的输入参数,修改特定全局变量,使被测函数处于某特定运行环境下,这两步属于测试驱动。然后调用被函数,最后判断测试结果,因为运行被测函数可能影响输入参数、全局变量与返回值,所以判断用例是否运行通过,观察对象也是这三者。在用例设计过程中,我们并不关心函数内局部变量如何声明,也不关心函数内逻辑过程如何处理,只关心被测对象的输入
46、与输出,这是一种典型的黑盒思维模式。准确来说,4GWM是一种灰盒测试方法,尽管操作方式是黑盒的,但测试设计是白盒的,因为看得见源码,测试设计可以有针对性的进行,测试过程评估也是白盒的,运行一遍用例后,查看哪些代码行有没跑到,再有针对性补充用例。所以,我们从整体来看,4GWM是介于黑盒与白盒之间的灰盒测试。,条件测试,条件测试方法注重于测试程序中的条件。是检查程序模块中所包含逻辑条件的测试用例设计方法。 条件程序中的条件分为简单条件和复合条件。简单条件是一个布尔变量或一个可能带有NOT(“!”)操作符的关系表达式。关系表达式的形式如:E1关系操作符E2其中E1和E2是算术表达式,而关系操作符是下
47、列之一:“”、“”、“=”、“”(“!=”)、“”、或“”。复合条件由简单条件通过逻辑运算符(AND、OR、NOT)和括号连接而成,不含关系表达式的条件称为布尔表达式。所以条件的成分类型包括布尔操作符、布尔变量、布尔括弧(括住简单或复杂条件)、关系操作符或算术表达式。,条件测试,条件的错误类型 如果条件不正确,则至少有一个条件成分不正确,这样,条件的错误类型如下: 布尔操作符错误(遗漏布尔操作符,布尔操作符多余或布尔操作符不正确); 布尔变量错误; 布尔括弧错误; 关系操作符错误; 算术表达式错误。,条件测试,条件测试的目的条件测试是测试程序条件错误和程序的其他错误。如果程序的测试集能够有效地
48、检测程序中的条件错误,则该测试集可能也会有效地检测程序中的其他错误。此外,如果测试策略对检测条件错误有效,则它也可能有效地检测程序错误。,条件测试,条件测试策略 穷举测试 (条件组合)有n个变量的布尔表达式需要2n个可能的测试(n0)。这种策略可以发现布尔操作符、变量和括弧的错误,但是只有在n很小时实用。 分支测试分支测试可能是最简单的条件测试策略,它是真假分支必须至少执行一次的路径策略,对于复合条件C,C的真分支和假分支以及C中的每个简单条件都需要至少执行一次。,条件测试 - 分支测试,域测试(Domain testing)域测试是对于大于、小于和等于值的测试路径策略。 域测试要求从有理表达
49、式中导出三个或四个测试,有理表达式的形式如:E1关系操作符E2需要三个测试分别用于计算E1的值是大于、等于或小于E2的值。如果关系操作符错误,而E1和E2正确,则这三个测试能够发现关系算子的错误。为了发现E1和E2的错误,计算E1小于或大于E2的测试应使两个值间的差别尽可能小。,条件测试,BRO(branch and relational)测试 如果在一个判定的复合条件表达式中每个布尔变量和关系运算符最多只出现一次,而且没有公共变量,应用一种称之为BRO(分支与关系运算符)的测试法可以发现多个布尔运算符或关系运算符错,以及其他错误。 BRO策略引入条件约束的概念。设有n个简单条件的复合条件C,其条件约束为D= (D1,D2,Dn) ,其中Di(0in)是条件C中第i个简单条件的输出约束。如果在C的执行过程中,其每个简单条件的输出都满足D中对应的约束,则称条件C的条件约束D由C的执行所覆盖。对于布尔变量或布尔表达式B,B的输出约束必须是真(t)或假(f);对于关系表达式,其输出约束为符号、=、。,