1、第 四 章,白盒测试方法,第四章 白盒测试方法,白盒测试的基本概念,白盒测试:把程序看成装在一个透明的盒子里,程序的结构和处理过程完全可见,按照程序的内部逻辑测试程序,以检查程序中的每条通路是否都能按照预先要求正确工作。白盒测试针对被测单元的内部进行,它的突出特点是基于被测程序的源代码,而不是基于软件的规格说明书。,白盒测试方法的分类,静态测试:着重在于纠正软件系统在描述、表示和规格上的错误,是进一步测试的前提,方法包括: 桌面检查(Desk checking) 代码评审(Code reading/review) 走查(Walkthroughs)动态测试:根据程序的控制结构设计测试用例,要求:
2、 保证一个模块中的所有独立路径至少执行一次 对所有逻辑值均需测试True和False 在上下边界及可操作范围内运行所有循环 检查内部数据结构以确保其有效性,控制流图的图形符号,第四章 白盒测试方法,逻辑覆盖以程序的内部逻辑结构为基础,主要分以下几种方式:,逻 辑 覆 盖,语句覆盖 判定覆盖 条件覆盖 判定条件覆盖 条件组合覆盖 路径覆盖,语 句 覆 盖 Statement Coverage,设计足够多的测试用例,使得程序中的每个语句至少执行一次。,1 语 句 覆 盖,语 句 覆 盖,测试用例:a = 10, b = 5,int foo(int a, int b) return a / b; ,
3、尽管语句覆盖率达到了所谓的100%,但是却没有发现最简单的Bug,如:b=0时会出现一个除零异常。,判 定 覆 盖 Dicision Coverage,不仅每个语句都必须至少执行一次,而且每个判定表达式的每种可能的结果都应该至少执行一次,即每个判定的“真”分支和“假”分支至少都执行一次。判定覆盖又称分支覆盖。,2 判定覆盖(分支覆盖),1,2,条 件 覆 盖 Condition Coverage,不仅每个语句都必须至少执行一次,而且每个判定表达式中的每个条件都取到各种可能的结果,即每个条件的“真”条件和“假”条件至少都执行一次。,3 条 件 覆 盖,A1, B!=0, A=2, X1,条件覆盖
4、1:,1,2,程序中共有4个条件8个结果,A1, B=0,A=2, X1 (全真) A=1, B!=0, A!=2, X=1(全假),条件覆盖2:,请思考:这个条件覆盖的测试用例是否完全?,真假 混搭,条件覆盖特点,判定覆盖 vs 条件覆盖,判定覆盖:(1)a = 5, b = 5 覆盖了分支一(2)a = 15, b = 15覆盖了分支二,int foo(int a, int b) if (a 10 | b 10) / 判定return 0; / 分支一elsereturn 1; / 分支二 ,条件覆盖:(1)a = 5, b = 5 true,true(2)a = 15, b = 15fa
5、lse,false,假如测试用例设计为: (1)a = 5, b = 15true, false 分支一 (2)a = 15, b = 5 false, true 分支一这时候,虽然做到了条件覆盖,但却没有把两个判定分支都执行到,没有做到判定覆盖。*结论:判定覆盖不一定包含条件覆盖,条件覆盖也不一定包含判定覆盖,判 定 条 件 覆 盖 Decision/Condition Coverage,设计足够多的测试用例,使得判定中的每个条件都取到各种可能的值,而且每个判定表达式也都取到各种可能的结果。,4 判定/条件覆盖,*表面上看,判定条件覆盖测试了所有条件的所有可能结果,但事实上有些条件会掩盖另一
6、些条件。例如,在“与”表达式中,如果某一条件为“假”,则整个判定的值为“假”,这个判定中的其他条件就不起作用了。同样地,若在“或”表达式中某一条件为“真”,则整个判定的值为“真”,其它条件也就不起作用了。因此,采用判定条件覆盖时,判定表达式中的错误不一定能测试出来。,1,2,条 件 组 合 覆 盖 Condition Combination Coverage,设计足够多的测试用例,使得每个判定表达式中条件的各种可能组合都至少出现一次。,5 条件组合覆盖,a点的所有条件组合: (1)A1, B0 ; (2)A1, B0 (3)A 1, B0 ; (4)A 1, B0b点的所有条件组合: (5)A
7、2, x1 ; (6)A2, x1 (7)A 2, x1 ; (8)A 2, x1,a,b,一组测试用例: 满足(1)和(5): A2, B0, x4 满足(2)和(6): A2, B1, x1 满足(3)和(7): A1, B0, x2 满足(4)和(8): A1, B1, x1,第二组测试用例: 满足(1)和(8): A3, B0, x1 满足(2)和(7): A3, B1, x2 满足(3)和(6): A无取值, B0, x1 满足(4)和(5): A无取值, B1, x2,条件覆盖 vs 条件组合覆盖,条件覆盖 (3个条件6个结果): (1) a = 5, b = 7, c = 6(全
8、真) (2) a = 7, b = 9, c = 4(全假),int foo(int a, int b) if (a 5) ) /判定hreturn 1; ,条件组合覆盖:k条件h条件: (1) c 5; (2) c = 5测试用例,(1) a = 8 (3) a = 6, b =6, b = 8,(1) a = 7, b = 7, c = 6 (2) a = 5, b = 7, c = 6 (3) a = 5, b = 7, c = 6 (4) a = 5, b = 7, c = 6,1. 语句覆盖 a = 5, b = 5, nReturn = 11 语句覆盖率100%2. 判定覆盖a =
9、 5, b = 5, nReturn = 11a = 15, b = 15 nReturn = 0 判定覆盖率100%3. 条件覆盖a = 5, b = 15 nReturn = 1a = 15, b = 5 nReturn = 10条件覆盖率100%,上面三种覆盖率都达到了100%,很好!但是,仔细分析可以看出,nReturn的结果一共有四种可能的返回值:0、1、 10、11, 而上面每种测试方式只覆盖了部分返回值,可见以上任一覆盖方式虽然覆盖率很高,但是并没有测试完全。,int foo(int a, int b) int nReturn = 0;if (a 10)nReturn += 1;
10、 / 分支一if (b 10)nReturn += 10; / 分支二return nReturn; ,路 径 覆 盖 Path Coverage,设计足够多的测试用例,使程序的每一条可能路径都至少执行一次。,路 径 覆 盖,路径覆盖将所有可能的返回值都测试到了,这正是它被很多人认为是“最强的覆盖”的原因。,int foo(int a, int b) int nReturn = 0;if (a 10)nReturn += 1; / 分支一if (b 10)nReturn += 10; / 分支二return nReturn; ,测试用例: a=5, b=5, nReturn = 0a=15,
11、b=5, nReturn = 1a=5, b=15, nReturn = 10a=15, b=15, nReturn = 11 路径覆盖率100%,路 径 覆 盖,1,4,2,3,六种形式的逻辑覆盖,各种测试方法都不能保证程序的正确性,但测试的目的并不是为了保证其正确,而是为了尽可能找出程序中隐藏的故障。,语句覆盖 判定覆盖 条件覆盖 判定条件覆盖 条件组合覆盖 路径覆盖,(e)两个串行的 分支结构的N-S图,(a)顺序型,(b)选择型,(c)Do-While型,(d)Do-Until型,N-S图表示的基本控制结构,最少测试用例数=(5*3+1)*3=48,5,3,3,第四章 白盒测试方法,基
12、本路径测试,又称独立路径测试,是指在程序控制流图的基础上,分析控制构造的环路复杂性,导出独立可执行路径集合,设计测试用例的方法。设计出的测试用例要保证在测试中,程序的每一个独立可执行路径至少要执行一次。循环体最多只执行一次。,path1:1 11path2:1 - 2 - 3 - 4 - 5 - 10 - 1 11path3:1 - 2 - 3 - 6 - 8 - 9 - 10 - 1 11path4:1 - 2 - 3 - 6 - 7 - 9 - 10 - 1 - 11,基本路径集,导出程序流程图的拓扑结构流图(控制流程图) 计算流图的环路复杂性 确定只包含独立路径的基本路径集 设计测试用例
13、,基本(独立)路径测试步骤,int test2( int x, int y ) int k = 0; if (x 0) if ( y = 0 ) k = x + 100; else if ( y = 1 )k = k + 10; else k = 20; return k; ,基本路径测试,int test2( int x, int y ) int k = 0; if (x 0) if ( y = 0 ) k = x + 100; else if ( y = 1 ) k = k + 10; else k = 20; / if ( y = 0 ) / if( x0 ) return k; ,第一
14、步: 给程序语句编号,第二步:画出程序流图,路径1: 1, 2, 10路径2:1,2,3,4,10路径3:1,2,3,5,6,7,10路径4:1,2,3,5,6,8,9,10,第三步:找出基本路径,测试用例:x 0 , y=0, k=x+100测试用例:x0, y=1, k=10测试用例:x0, y!= 0, y!=1, k=20,第四步:设计测试用例,环路复杂度为4,第三步:计算环路复杂度,int test(int x, int y) int k = 0; if( x 0) if( y = 0 ) k = x + 100; else if ( y = 1 ) k += 10; else k
15、= 20; return k; ,第四章 白盒测试方法,循 环 测 试,简单循环,串接循环,嵌套循环,跳过循环 只通过循环一次 通过循环两次 通过循环m次,其中m n-1 通过循环n1,n,n+1次,简单循环测试,注: n是允许通过循环的最大次数,嵌套循环测试,对最内层循环做简单循环的全部测试。所有其它层的循环变量置为最小值。 逐步外推,对其外面一层循环进行测试。测试时保持所有外层循环的循环变量取最小值,所有其它嵌套内层循环的循环变量取“典型”值。 反复进行,直到所有各层循环测试完毕。 对全部各层循环同时取最小循环次数,或者同时取最大循环次数,串接循环测试,如果串接循环的各个循环都彼此独立,则
16、可以使用简单循环的方法来测试串接循环。当循环不独立时,使用测试嵌套循环的方法来测试串接循环。,第四章 白盒测试方法,面向对象的白盒测试,类测试一般有两种主要的方式:功能性测试和结构性测试,即对应于传统结构化软件的黑盒测试和白盒测试。 结构性测试要考虑程序的代码是否正确,对类中的方法进行测试,它把类作为一个单元来进行测试。测试分为两层:第一层考虑类中各独立方法的代码;第二层考虑方法之间的相互作用。 对于一个类的测试要保证类在其状态的代表集上能够正确工作,构造函数的参数选择以及消息序列的选择都要满足这一准则。,面向对象的白盒测试方法的单独测试,结构性测试的第一层是考虑各独立的方法,这可以与过程的测
17、试采用同样的方法,两者之间最大的差别在于方法改变了它所在实例的状态,这就要取得隐藏的状态信息来估算测试的结果,传给其它对象的消息被忽略,而以桩来代替,并根据所传的消息返回相应的值,测试数据要求能完全覆盖类中代码,可以用传统的测试技术来获取。,面向对象的白盒测试方法的综合测试,第二层要考虑一个方法调用本对象类中的其它方法和从一个类向其它类发送信息的情况。单独测试一个方法时,只考虑其本身执行的情况,而没有考虑动作的顺序问题,测试用例中加入了激发这些调用的信息,以检查它们是否正确运行了。对于同一类中方法之间的调用,一般只需要极少甚至不用附加数据,因为方法都是对类进行存取,故这一类测试的准则是要求遍历
18、类的所有主要状态。,第四章 白盒测试方法,程序插桩方法是借助往被测程序中插入操作来实现测试目的的方法。该法是软件动态测试中的一种基本测试手段,有着广泛的应用。如果我们想要了解一个程序在某次运行中所有可执行语句被覆盖的情况,或是每个语句的实际执行次数,最好的办法是利用插桩技术。,插 桩 测 试,程序插桩时需要着重考虑:探测哪些信息; 在程序的什么部位设置探测点; 需要设置多少个探测点。,域测试(Domain Testing),域测试是一种基于程序结构的测试方法。Howden把程序中出现的错误分为域错误、计算型错误和丢失路径错误三种。 如果程序的控制流有错误,对于某一特定的输入可能执行的是一条错误
19、路径,这种错误称为路径错误,也叫做域错误。 如果对于特定输入执行的是正确路径,但由于赋值语句的错误致使输出结果不正确,则称此为计算型错误。 另外一类错误是丢失路径错误。,域测试是主要针对域错误进行的程序测试。 域测试方法基于对输入空间的分析。 测试的理想结果就是检验输入空间中的每一个输入元素是否都产生正确的结果。 域测试正是在分析输入域的基础上,选择适当的测试点以后进行测试的。 域测试有两个致命的弱点:一是为进行域测试对程序提出的限制过多,二是当程序存在很多路径时,所需的测试点也很多。,域测试(Domain Testing),符号测试方法,基本思想是允许程序的输入不仅仅是具体的数值数据,而且包括符号值,符号值可是基本符号变量值,也可是这些符号变量值的一个表达式。 普通测试执行的是算术运算,符号测试则是执行代数运算。 符号测试方法使用问题的关键在于开发出比传统的编译器功能更强,能够处理符号运算的编译器和解释器。,Z路径覆盖测试方法,称简化循环意义下的路径覆盖为Z路径覆盖。 即无论循环的形式和实际执行循环体的次数多少,我们只考虑循环一次和零次两种情况。,(a) (b) (c),Any Questions,