按是否查看代码的角度划分:黑盒测试、白盒测试、灰盒测试

按是否查看代码的角度划分

1.黑盒测试(Black-box Testing)

黑盒测试也是功能测试,测试中把被测的软件当成一个黑盒子,不关心盒子的内部结构是什么,只关心软件的输入数据和输出数据。

黑盒测试也称功能测试,它是通过测试来检测每个功能是否都能正常使用。在测试中,把程序看作一个不能打开的黑盒子,在完全不考虑程序内部结构和内部特性的情况下,在程序接口进行测试,它只检查程序功能是否按照需求规格说明书的规定正常使用,程序是否能适当地接收输入数据而产生正确的输出信息。黑盒测试着眼于程序外部结构,不考虑内部逻辑结构,主要针对软件界面和软件功能进行测试。

黑盒测试是以用户的角度,从输入数据与输出数据的对应关系出发进行测试的。很明显,如果外部特性本身设计有问题或规格说明的规定有误,用黑盒测试方法是发现不了的。

作用

黑盒测试法注重于测试软件的功能需求,主要试图发现下列几类错误。

功能不正确或遗漏;

界面错误;

输入和输出错误;

数据库访问错误;

性能错误;

初始化和终止错误等。

优点 

1、对于子系统甚至系统,效率要比白盒测试高。 

2、测试人员不需要了解实现的细节,包括特定的编程语言。 

3、测试人员和编程人员彼此独立。 

4、从用户的角度进行测试,很容易理解和接受。 

5、有助于暴露规格的不一致或有歧义的问题。 

6、测试用例可以在规格完成后马上进行。

缺点 

1、只有一小部分输入被测试到,要测试每个可能的输入几乎不可能。 

2、没有清晰、简明的规格,测试用例很难设计。 

3、如果测试人员不被告知开发人员已经执行过的用例,在测试数据上会存在不必要的重复。 

4、有很多程序路径没有被测试到。 

5、不能直接针对特定程序段测试,而这些程序段可能很复杂,有可能隐藏更多的问题。 

6、大部分和研究相关的测试都是直接针对白盒测试的。

测试用例设计方法

从理论上讲,黑盒测试只有采用穷举输入测试,把所有可能的输入都作为测试情况考虑,才能查出程序中所有的错误。实际上测试情况有无穷多个,人们不仅要测试所有合法的输入,而且还要对那些不合法但可能的输入进行测试。这样看来,完全测试是不可能的,所以我们要进行有针对性的测试,通过制定测试案例指导测试的实施,保证软件测试有组织、按步骤,以及有计划地进行。黑盒测试行为必须能够加以量化,才能真正保证软件质量,而测试用例就是将测试行为具体量化的方法之一。具体的黑盒测试用例设计方法包括等价类划分法、边界值分析法、错误推测法、因果图法、判定表驱动法、正交试验设计法、功能图法、场景法等。

等价类划分法

等价类是指某个输入域的子集合。在该子集合中,各个输入数据对于揭露程序中的错误都是等效的,并合理地假定:测试某等价类的代表值就等于对这一类其它值的测试.因此,可以把全部输入数据合理划分为若干等价类,在每一个等价类中取一个数据作为测试的输入条件,就可以用少量代表性的测试数据.取得较好的测试结果.等价类划分可有两种不同的情况:有效等价类和无效等价类。

有效等价类:是指对于程序的规格说明来说是合理的,有意义的输入数据构成的集合.利用有效等价类可检验程序是否实现了规格说明中所规定的功能和性能。

无效等价类:与有效等价类的定义恰巧相反。

设计测试用例时,要同时考虑这两种等价类.因为,软件不仅要能接收合理的数据,也要能经受意外的考验.这样的测试才能确保软件具有更高的可靠性。

划分等价类的原则

①  在输入条件规定了取值范围或值的个数的情况下,则可以确立一个有效等价类和两个无效等价类。

例:输入值是学生成绩,范围是0~100:

 

②  在输入条件规定了输入值的集合或者规定了“必须如何”的条件的情况下,可确立一个有效等价类和一个无效等价类。

③  在输入条件是一个布尔类型的情况下,可确定一个有效等价类和一个无效等价类。

④在规定了输入数据的一组值(假定n个),并且程序要对每一个输入值分别处理的情况下,可确立n个有效等价类和一个无效等价类。

⑤在规定了输入数据必须遵守的规则的情况下,可确立一个有效等价类(符合规则)和若干个无效等价类(从不同角度违反规则)。

⑥在确知已划分的等价类中各元素在程序处理中的方式不同的情况下,则应再将该等价类进一步的划分为更小的等价类。

建立等价类表

设计测试用例:在确立了等价类后,可建立等价类表,列出所有划分出的等价类:

确定测试用例

输入条件 有效等价类 或  无效等价类

然后从划分出的等价类中按以下三个原则设计测试用例:

①  为每一个等价类规定一个唯一的编号。

②  设计一个新的测试用例,使其尽可能多地覆盖尚未被覆盖地有效等价类,重复这一步.直到所有的有效等价类都被覆盖为止。

③  设计一个新的测试用例,使其仅覆盖一个尚未被覆盖的无效等价类,重复这一步.直到所有的无效等价类都被覆盖为止。

举例:判断三角形类别

【问题描述】程序要求:输入三个整数 a 、 b 、 c 分别作为三角形的三边长度,通过程序判定所构成的三角形的类型;当三角形为一般三角形、等腰三角形或等边三角形时,分别作处理 。 

【问题分析】

(1) 输入值域的显/隐式要求:A 整数、B 三个、C 正数、D 两边之和大于第三边、E 三边均不相等、F 两边相等但不等于第三边、G 三边相等;(D~G由输出值域的等价类隐性确定)

(2) 输出值域的等价类:R1={不构成三角形}、R2={一般三角形}、R3={等腰三角形}、R4={等边三角形};

【问题解答】
(1) 列出等价类表并编号 

(2) 设计覆盖有效等价类的测试用例 
 

(3) 设计覆盖无效等价类的测试用例 
 

【问题描述】程序要求:输入三个数 a 、 b 、 c 分别作为三角形的三边长度,通过程序判定所构成的三角形的类型;当三角形为一般三角形、等腰三角形或等边三角形时,分别作处理 。注:a、b、c非空。 

 

【问题分析】

(1) 输入值域的显/隐式要求:B 三个、C 正数、D 两边之和大于第三边、E 三边均不相等、F 两边相等但不等于第三边、G 三边相等;(D~G由输出值域的等价类隐性确定)

(2) 输出值域的等价类:R1={不构成三角形}、R2={一般三角形}、R3={等腰三角形}、R4={等边三角形};

【问题解答】
(1) 列出等价类表并编号 

 

 (2) 设计覆盖有效/无效等价类的测试用例

边界值分析法

边界值分析是通过选择等价类边界的测试用例。边界值分析法不仅重视输入条件边界,而且也必须考虑输出域边界。它是对等价类划分方法的补充。

(1)边界值分析方法的考虑:

长期的测试工作经验告诉我们,大量的错误是发生在输入或输出范围的边界上,而不是发生在输入输出范围的内部.因此针对各种边界情况设计测试用例,可以查出更多的错误。

使用边界值分析方法设计测试用例,首先应确定边界情况.通常输入和输出等价类的边界,就是应着重测试的边界情况.应当选取正好等于,刚刚大于或刚刚小于边界的值作为测试数据,而不是选取等价类中的典型值或任意值作为测试数据。

(2)基于边界值分析方法选择测试用例的原则:

   1)如果输入条件规定了值的范围,则应取刚达到这个范围的边界的值,以及刚刚超越这个范围边界的值作为测试输入数据。

   2)如果输入条件规定了值的个数,则用最大个数,最小个数,比最小个数少一,比最大个数多一的数作为测试数据。

   3)根据规格说明的每个输出条件,使用前面的原则1)。

   4)根据规格说明的每个输出条件,应用前面的原则2)。

   5)如果程序的规格说明给出的输入域或输出域是有序集合,则应选取集合的第一个元素和最后一个元素作为测试用例。

   6)如果程序中使用了一个内部数据结构,则应当选择这个内部数据结构的边界上的值作为测试用例。

   7)分析规格说明,找出其它可能的边界条件。

举例:区间值的边界值取值问题

用边界值分析法,假定1<X<10,那么X在测试中应该取的边界值是( A )

X=1,X=2,X=9,X=10

X=2,X=9

X=1,X=10

X=1,X=5,X=6,X=10

这里涉及到开闭区间和离点的概念,在边界值分析时,有下面几个点:

上点:就是指得边界上得点,无论此时得域是开区间还是闭区间,开区间得话,上点就是在域外,闭区间得话,上点就是在域内。

离点:指得就是离上点最近得点,这里就跟是闭区间还是开区间就有关系了,如果是开区间,那么离点就在域内,如果是闭区间,那么离点就在域外。

内点:域内得任意点都是内点。

题目中给的是开区间,不包括等于的情况。这里上点是1和10,因为是开区间,所以离点是在区间内,即2和9。所以边界值要覆盖1 2 9 10。

上点很好理解,但是开区间的离点为什么在区间内,0和11需要覆盖吗?

其实可以这么理解,对开区间,范围不包括边界,上点是在范围之外的,所以需要再测一个在范围之内,又离上点最近的点,这个值就是范围内离上点最近的点。

另外,假如题目给的条件是1≦x≦10,那答案就是0 1 10 11,如果是1<x≦10,那答案就应该是1 2 10 11。

举例:判断三角形类别

【问题描述】程序要求:输入三个不超过200的整数 a 、 b 、 c 分别作为三角形的三边长度,通过程序判定所构成的三角形的类型;当三角形为一般三角形、等腰三角形或等边三角形时,结果打印出来 。 

【问题分析】

(1) 输入值域的显/隐式要求:A 整数、B 三个、C 正数、D 两边之和大于第三边、E 三边均不相等、F 两边相等但不等于第三边、G 三边相等;(D~G由输出值域的等价类隐性确定)

(2) 输出值域的等价类:R1={不构成三角形}、R2={一般三角形}、R3={等腰三角形}、R4={等边三角形};

(3)边界值:0、1、2、100、199、200、201

当仅有一个变量取边界值,其他取正常值,从一般边界值的角度考虑{1、2、100、199、200},(4n+1=13,n=3)如下表所示。

序号

输入及操作说明

期望的测试结果

1

1、100、100

等腰三角形

2

2、100、100

3

199、100、100

4

200、100、100

非三角形

5

100、1、100

等腰三角形

6

100、2、100

7

100、199、100

8

100、200、100

非三角形

9

100、100、1

等腰三角形

10

100、100、2

11

100、100、199

12

100、100、200

非三角形

13

100、100、100

等边三角形

当仅当有一个变量取边界值,其他取正常值,从健壮边界值的角度考虑{0、1、2、100、199、200、201},(6n+1=19,n=3) 如下表所示。

序号

输入及操作说明

期望的测试结果

1

0、100、100

非三角形

2

1、100、100

等腰三角形

3

2、100、100

4

199、100、100

5

200、100、100

非三角形

6

201、100、100

7

100、0、100

8

100、1、100

等腰三角形

9

100、2、100

10

100、199、100

11

100、200、100

非三角形

12

100、201、100

13

100、100、0

14

100、100、1

等腰三角形

15

100、100、2

16

100、100、199

17

100、100、200

非三角形

18

100、100、201

19

100、100、100

等边三角形

 当所有变量取边界值时,介于篇幅原因,可使用上述表中的边界值自行完成53、73个测试用例。

   

总结:

  由于多变量同时取边界值,关注的是变量同时取值对功能的影响,三角形问题的各个变量之间相对独立,因此对于三角形问题仅考虑使用一个变量取边界值,其他变量取正常值即可

错误推测法

错误推测法是基于经验和直觉推测程序中所有可能存在的各种错误,从而有针对性的设计测试用例的方法.

错误推测方法的基本思想: 列举出程序中所有可能有的错误和容易发生错误的特殊情况,根据他们选择测试用例。 例如,在单元测试时曾列出的许多在模块中常见的错误. 以前产品测试中曾经发现的错误等,这些就是经验的总结。还有,输入数据和输出数据为0的情况. 输入表格为空格或输入表格只有一行. 这些都是容易发生错误的情况。可选择这些情况下的例子作为测试用例。

它的要素共有三点,分别为:经验、知识、直觉。关于如何使用的问题,我们提炼出两点:

  1.列举出程序中所有可能有的错误和容易发生错误的特殊情况;

  2.根据他们选择测试用例。

  我们知道经验是错误推测法的一个重要要素,也就说带有主观性,那么这就决定了错误猜测法的优缺点,首先我们来看优点:

  1.充分发挥人的直觉和经验;

  2.集思广益;

  3.方便使用;

  4.快速容易切入;

  对应的缺点有:

  1.难以知道测试的覆盖率;

  2.可能丢失大量未知的区域;

  3.带有主观性且难以复制;

举例:手机终端通话功能

例如:测试手机终端的通话功能,可以设计哪些通话失败的情况来补充测试用例

     1、无SIM 插入是进行呼出(非紧急呼叫)

     2、插入已欠费SIM卡进行呼出

     3、射频器件损坏或无信号区域插入有效SIM卡呼出

     4、网络正常、插入有效SIM卡,呼无效号码(如1、888、33333、不输入任何号码等)

     5、网络正常,插入有效SIM卡,使用“快速拔号”功能呼出设置无效号码的数字

因果图法

前面介绍的等价类划分方法和边界值分析方法,都是着重考虑输入条件,但未考虑输入条件之间的联系,相互组合等。 考虑输入条件之间的相互组合,可能会产生一些新的情况. 但要检查输入条件的组合不是一件容易的事情,即使把所有输入条件划分成等价类,他们之间的组合情况也相当多. 因此必须考虑采用一种适合于描述对于多种条件的组合,相应产生多个动作的形式来考虑设计测试用例. 这就需要利用因果图(逻辑模型)。

因果图方法最终生成的就是判定表。它适合于检查程序输入条件的各种组合情况。

生成测试用例

(1) 分析软件规格说明描述中,哪些是原因(即输入条件或输入条件的等价类),哪些是结果(即输出条件),并给每个原因和结果赋予一个标识符。

(2) 分析软件规格说明描述中的语义。找出原因与结果之间,原因与原因之间对应的关系. 根据这些关系,画出因果图。

(3) 由于语法或环境限制,有些原因与原因之间,原因与结果之间的组合情况不可能出现. 为表明这些特殊情况,在因果图上用一些记号标明约束或限制条件。

(4) 把因果图转换为判定表。

(5) 把判定表的每一列拿出来作为依据,设计测试用例。

从因果图生成的测试用例(局部,组合关系下的)包括了所有输入数据的取TRUE与取FALSE的情况,构成的测试用例数目达到最少,且测试用例数目随输入数据数目的增加而线性地增加。

前面因果图方法中已经用到了判定表。判定表(Decision Table)是分析和表达多逻辑条件下执行不同操作的情况下的工具.在程序设计发展的初期,判定表就已被当作编写程序的辅助工具了.由于它可以把复杂的逻辑关系和多种条件组合的情况表达得既具体又明确。

因果图标识

 原因和结果之间的关系有: 
 

 

①恒等:若C1是1,则E1也是1;若C1是0,则E1也是0。 
②非:若C1是1,则E1是0;若C1是0,则E1是1。 
③或:若c1或c2是1,则E1是1;否则E1为0。 或的含义:只有所有条件都为0时,结果为0,有任何1个条件为1(或者所有条件为1)时,结果为1
④与:若c1和c2都是1,则E1为1;否则E1为0。与的含义:只有所有条件都为1时,结果为1,有任何一个条件为0(或者所有条件为0)那么结果为0.

因果图约束

约束条件符号: 

 

  

输入条件的约束有以下4类: 
1. E约束(互斥/异):a和b中至多有一个可能为1,即a和b不能同时为1。含义:可以不选,如果选,只能选1个 
2. I约束(或):a、b和c中至少有一个必须是1,即 a、b 和c不能同时为0。含义:至少选1个(可以多选,不能不选,最少得选1个) 
3. O约束(唯一);a和b必须有一个,且仅有1个为1。含义:有且只有1个(必须要选,而且只能选1个)

4. R约束();若a为1时,则b必须为1。而当a为0时,b的值不定。

输出条件约束类型 

输出条件的约束只有M约束(屏蔽/强制):若结果a是1,则结果b强制为0。而当a为0时,b的值不定。

因果图法测试用例的设计步骤

(1)  确定软件规格(需求)中的原因和结果

分析软件规格说明描述中,哪些是原因(即输入条件或输入条件的等价类),哪些是结果(即输出条件), 并给每个原因和结果赋予一个标识符。

(2)  确定原因和结果之间的逻辑关系

分析软件规格说明描述中的语义。找出原因与结果之间,原因与原因之间对应的关系。根据这些关系,画出因果图。

(3)  确定因果图中的各个约束(constraints)

由于语法或环境限制,有些原因与原因之间,原因与结果之间的组合情况下不可能出现。 为表明这些特殊情况,在因果图上用一些记号表明约束或限制条件。

(4)画出因果图并转换为决策表

(5)根据决策表设计测试用例

因果图法优缺点

优点:

①  考虑到了输入情况的各种组合以及各个输入情况之间的相互制约关系。

②  能够帮助测试人员按照一定的步骤,高效率的开发测试用例。

③  因果图法是将自然语言规格说明转化成形式语言规格说明的一种严格的方法,可以指出规格说明存在的不完整性和二义性。

缺点:

①  因果图来设计测试用例时,作为输入条件的原因与输出结果之间的因果关系,有时很难从软件需求规格说明中得到。

②  而且往往因果关系非常庞大,以至于据此因果图而得到的测试用例数目多的惊人,给软件测试,特别是手工测试带来沉重的负担,为了有效地,合理地减少测试的工时与费用,可利用正交实验设计方法进行测试用例的设计。

举例:自动售货机

产品说明书:有一个处理单价为1元5角钱的盒装饮料的自动售货机软件。若投入1元5角硬币,按下“可乐”、“雪碧”、或“红茶”按钮,相应的饮料就送出来。若投入的是2元硬币,在送出饮料的同时退还5角硬币。

 

 

判定表法

1.判定表是分析和表达多逻辑条件下执行不同操作的情况的工具。判定表通常由四个部分组成:

条件桩(Condition Stub):列出了问题的所有条件.通常认为列出的条件的次序无关紧要。

动作桩(Action Stub):列出了问题规定可能采取的操作.这些操作的排列顺序没有约束。

条件项(Condition Entry):列出针对它左列条件的取值.在所有可能情况下的真假值。

动作项(Action Entry):列出在条件项的各种取值情况下应该采取的动作。

 

2.规则:任何一个条件组合的特定取值及其相应要执行的操作.在判定表中贯穿条件项和动作项的一列就是一条规则.显然,判定表中列出多少组条件取值,也就有多少条规则,既条件项和动作项有多少列。

 

3. 判定表的化简:合并判定表中两条或多条具有相同动作,并且其条件项之间存在着极为相似关系的规则这一过程。

4. 判定表使用场景:如果程序中多个条件决定一个动作,并且每个条件的取值只有两种,且条件和动作之间的逻辑关系明确

5. 优点:能够将复杂的问题按照各种可能的情况全部列举出来,简明并且可以避免遗漏。

判定表的建立步骤:(根据软件规格说明)

1.列出所有的条件桩和动作桩。

2.确定规则的个数。假如有n个条件.每个条件有两个取值(0,1),故有2n种规则。

3.填入条件项。

4.填入动作项.等到初始判定表。

5.简化.合并相似规则(相同动作)。

有两个或者多条规则具有相同的动作,并且条件项之间存在极为相似的关系就可以进行合并。

判定表设计测试用例的条件:

规格说明以判定表形式给出,或很容易转换成判定表。

①  条件的排列顺序不会也不影响执行哪些操作。

②  规则的排列顺序不会也不影响执行哪些操作。

③  每当某一规则的条件已经满足,并确定要执行的操作后,不必检验别的规则。

④  如果某一规则得到满足要执行多个操作,这些操作的执行顺序无关紧要。

判定表法优缺点

判定表的优点:

      1)  充分考虑了输入条件简的组合,对组合情况覆盖充分;

      2)  最终每个用例覆盖多种输入情况,有利于提高测试效率;

      3)  设计过程中,对输入条件间的约束关系做了考虑,避免了无效用例,用例的有效性高;

      4)  能同时得出每个测试项目的预期输出。

判定表的缺点:

      1)  当被测试特性输入较多时,会造成判定表规格庞大;

      2)  输入之间的约束条件不能有效区分输入是否确实需要进行组合测试,会造成不需要组合测试的输入做了组合,从而产生用例冗余。

举例:判断三角形类别

 

 

 

 

正交试验设计法

就是使用已经造好了的正交表格来安排试验并进行数据分析的一种方法,目的是用最少的测试用例达到最高的测试覆盖率。

使用正交试验设计法首先要知道正交表,正交表是研究多因素多水平的一种设计方法,它是格局正交性从全面试验中挑选出部分有代表性的点进行试验,这些有代表性的点具备了“均匀分散,齐整可比”的特点,正交试验设计是一种基于正交表的、高效率、快速、经济的试验设计方法。

正交表由三个成分构成:

Runs:正交表的行数,即实验的次数;

Factors:正交表的列数,即因素数;

Levels:水平数,任何单个因素能够取得的值的最大个数。正交表中的包含的值为从0到数“水平数-1”或从1到“水平数”

正交表的表现形式是:L行数(水平数因素数)    L runs(levels^factors  )。

设计过程

1)确定试验因素及水平数;

2)选用合适的正交表;

3)列出试验方案及试验结果;

4)对正交试验设计结果进行分析,包括极差分析和方差分析;

5)确定最优或较优因素水平组合。

用正交表设计测试用例的步骤:

1. 有哪些因素(变量);

2. 每个因素有哪几个水平(变量的取值):用等价类划分出来的;

3. 选择一个合适的正交表;

4. 把变量的值映射到表中;

5. 把每一行的各因素水平的组合作为一个测试用例;

6. 加上你认为可以且没有在表中出现的组合。

如何选择正交表呢?取行数最少的一个,情况分三种:

1.因素数(变量)、水平数(变量值)相符;

2.因素数不相同: 取因素数最接近但略大的实际值的表;

3.水平数不相同: 有五个因素(变量)A、B、C、D和E。两个因素有两个水平(变量的取值)、两个因素有三个水平,一个因素有六个水平。行数取最少的一个( 行数取最少的一个(L49(78)、 L18(3661)

教你用Minitab进行正交试验设计(极差)分析

首先,根据实验要求,确定你实验条件的因素、水平数,最好通过列表形式明确(如图:以影响大豆出油率为例)。

 

然后,可以通过Minitab创建以上确定的正交表,依次选择工具栏“统计”—“DOE”—“田口”—“创建田口设计”选项,调出“田口设计”对话框。

如图:

在“田口设计”对话框中,根据需求选择合适的因素、水平数,并点击“设计”按钮,选择合适正交表。

注意:要考虑到试验过程中的误差,所选正交表安排完因素后,要有一列空白列,以考察试验误差进行方差分析。(故本例:选4因素,3水平,L9表)。

如图,创建的“四因素三水平正交表”(注意:此处不考虑交互作用)。

 

 

在正交设计表等的基础上,将所选正交表中各列的“数字”换成对应因素的具体“实验水平值”(每一因素的某一水平均唯一对应一个实验条件值),便形成了试验方案。如图:

此时可以根据此表安排实验方案。

 

经过实验后,得到对应的数据结果后,填入正交表对应位置(本例:“大豆出油率/%”),进行实验数据分析。如图:

 

接着可进行数据分析:依次选择工具栏“统计”—“DOE”—“田口”—“分析田口设计”选项,调出“分析田口设计”对话框。如图:

 

 

然后,将实验数值列选择到“响应数据位于”(本例:C5 “大豆出油率/%”)框内,再点击“分析”按钮,选择要分析的项(本例:均值)如图:

最后,依次点击“确定”按钮,即可得极差分析结果(如图)。本例中由于大豆出油率越大越好(B>A>D>C),所以最优水平为:B3 A2 D1 C2

 

另外,Minitab软件还进行方差分析哦,(这里不再详述,请自行学习!)。

希望能对你有帮助!

 

场景法

软件几乎都是用事件触发来控制流程的,事件触发的情景便形成了场景,而同一事件不同的触发顺序和处理结果就形成事件流。这种在软件设计方面的思想也可以引入到软件测试中,可以比较生动地描绘出事件触发时的情景,有利于测试设计者设计测试用例,同时使测试用例更容易理解和执行。

场景法组成:基本流和备选流:如下图所示,图中经过用例的每条路径都用基本流和备选流来表示,直黑线表示基本流,是经过用例的最简单的路径。备选流用不同的色彩表示,一个备选流可能从基本流开始,在某个特定条件下执行,然后重新加入基本流中(如备选流1和3);也可能起源于另一个备选流(如备选流2),或者终止用例而不再重新加入到某个流(如备选流2和4)。

 

备选流

每个经过用例的可能路径,可以确定不同的用例场景。从基本流开始,再将基本流和备选流结合起来,可以确定以下用例场景:

场景 1 基本流

场景 2 基本流 备选流 1

场景 3 基本流 备选流 1 备选流 2

场景 4 基本流 备选流 3

场景 5 基本流 备选流 3 备选流 1

场景 6 基本流 备选流 3 备选流 1 备选流 2

场景 7 基本流 备选流 4

场景 8 基本流 备选流 3 备选流 4

场景法的核心概念

1、基本流(正确流):模拟用户正确的操作流程

目的:验证软件的业务流程和主要功能

2、备选流(错误流):模拟用户错误的操作流程

目的:验证软件的错误处理能力

场景法的本质

1、场景法是一种基于等价类划分的测试技术(技术层面)

2、场景法的应用是基于对软件业务(需求)的深入理解(业务层面)

用例设计步骤

1. 根据说明,描述出程序的基本流及各项备选流

2. 根据基本流和各项备选流生成不同的场景

3. 对每一个场景生成相应的测试用例

4. 对生成的所有测试用例重新复审,去掉多余的测试用例,测试用例确定后,对每一个测试用例确定测试数据值

举例:分析ATM取款机的场景流程

例子:分析ATM取款机的场景流程,并设计测试用例和测试数据 

1、根据需求,找到基本流和备选流(找出正确的操作流程和可能出错的环节)

基本流:1.插入磁卡

     2.ATM验证账户正确

     3.输入密码正确,通过验证

     4.输入取款金额

     5.取出金额

     6.取卡

备选流一:账户不存在或者受限制

备选流二:密码不正确,还有输入机会

备选流三:密码不正确,没有输入机会

备选流四:卡中余额不足

备选流五:ATM机中余额不足

备选流六:超过每日最大提款限额

备选流七:输入金额非100的倍数

 

2.白盒测试(White-box Testing)

白盒测试又称结构测试、透明盒测试、逻辑驱动测试或基于代码的测试。盒子指的是被测试的软件,白盒指的是盒子是可视的,你清楚盒子内部的东西以及里面是如何运作的。

"白盒"法全面了解程序内部逻辑结构、对所有逻辑路径进行测试。"白盒"法是穷举路径测试。在使用这一方案时,测试者必须检查程序的内部结构,从检查程序的逻辑着手,得出测试数据。白盒测试是指打开盒子,去研究里面的源代码和程序结果。

白盒测试也是接口测试的一种。

目的

1.保证一个模块中的所有独立路径至少被执行一次;

2.对所有的逻辑值均需要测试真、假两个分支;

3.在上下边界及可操作范围内运行所有循环;

4.检查内部数据结构以确保其有效性。

测试方法

白盒测试的测试方法有代码检查法、静态结构分析法、静态质量度量法、逻辑覆盖法、基本路径测试法、域测试、符号测试、Z路径覆盖和程序变异。

白盒测试法的覆盖标准有逻辑覆盖、循环覆盖和基本路径测试。

覆盖标准

逻辑覆盖有:语句覆盖、判定覆盖(分支覆盖)、条件覆盖、判定/条件覆盖、条件组合覆盖、路径覆盖;

控制结构覆盖有:基本路径测试、循环测试、条件测试、数据流测试 

代码检查法

   代码检查是白盒测试的一种静态测试方法,是一种对程序代码进行静态检查。代码检查包括桌面检查、代码审查和走查等,主要检查:

  1. 检查代码和设计的一致性;
  2. 代码的可读性及对软件设计标准的遵循情况;
  3. 代码逻辑表达的正确性;
  4. 代码结构的合理性;
  5. 发现违背程序编写标准的问题,程序中不安全、不明确和模糊的部分,找出程序中不可移植部分;
  6. 违背程序编程风格的内容,包括变量检查、命名和类型审查、程序逻辑审查、程序语法检查和程序结构检查等内容。

代码检查方法

(1)  桌面检查:

这是一种传统的检查方法,由程序员检查自己编写的程序。程序员在程序通过编译之后,对源程序代码进行分析、检验,并补充相关文档,目的是发现程序中的错误。由于程序员熟悉自己的程序及其程序设计风格,桌面检查由程序员自己进行可以节省很多的检查时间,但应避免主观片面性。

(2)代码审查
    由若干程序员和测试员组成一个审查小组,通过阅读、讨论和争议,对程序进行静态分析的过程。代码审查分两步:第一步,小组负责人提前把设计规格说明书、控制流程图、程序文本及有关要求、规范等分发给小组成员,作为审查的依据。小组成员在充分阅读这些材料后,进入审查的第二步,召开程序审查会。在会上,首先由程序员逐句简介程序的逻辑。在此过程中,程序员或其他小组成员可以提出问题,展开讨论,审查错误是否存在。实践表明,程序员在讲解过程中能发现许多原来自己没有发现的错误,而讨论和争议则促进了问题的暴露。
    在会前,应当给审查小组每个成员准备一份常见错误的清单,把以往所有可能发生的常见错误罗列出来,供与会者对照检查,以提高审查的失效。这个常见的错误清单也成为检查表,它把程序中可能发生的各种错误进行分类,对每一类错误列出尽可能多的典型错误,然后把它们制成表格,供再审查时使用。
(3)走查
    与代码审查基本相同,分为两步,第一步也是把材料分给走查小组的每个成员,让他们认真研究程序,然后再开会。开会的程序与代码审查不同,不是简单地读程序和对照错误检查表进行检查,而是让与会者“充当”计算机,即首先由测试组成员为所测试程序准备一批有代表性的测试用例,提交给走查小组。走查小组开会,集体扮演计算机角色,让测试用例沿程序的逻辑运行一遍,随时记录程序的踪迹,供分析和讨论用。

代码检查应在编译和动态测试之前进行,在检查前,应准备好需求描述文档、程序设计文档、程序的源代码清单、代码编译标准和代码缺陷检查表等。在实际使用中,代码检查能快速找到缺陷,发现30%~70%的逻辑设计和编码缺陷,而且代码检查看到的问题本身而非征兆。但是代码检查非常耗费时间,而且代码检查需要知识和经验的积累。
    代码检查可以使用测试软件进行自动化测试,以利于提高测试效率,降低劳动强度,或者使用人工进行测试,以充分发挥人力的逻辑思维能力。

代码检查项目

变量交叉引用表;标号的交叉引用表;检查子程序、宏、函数;等价性检查;常量检查;标准检查;风格检查;比较控制流;选择、激活路径;补充文档
根据检查项目可以编制代码规则、规范和检查表等作为测试用例,如编码规范、代码检查规范、缺陷检查表等。

编码规范

编码规范是指程序在编写过程中必须遵循的规则,一般会详细制定代码的语法规则、语法格式等。

代码检查规范

在代码检查中,需要依据被测软件的特点,选用适当的标准与规则规范。在使用测试软件进行自动化代码检查时,测试工具一般会内置许多的编码规则。在自动化测试基础上使用桌面检查、代码走查、代码审查等人工检查的方法仔细检查程序的结构、逻辑等方面的缺陷。

缺陷检查表

在进行人工代码检查时,代码缺陷检查表是我们用到的测试用例。代码缺陷检查表中一般包括容易出错的地方和在以往的工作中遇到的典型错误。

静态结构分析法

在静态结构分析中,测试者通过使用测试工具分析程序源代码的系统结构、数据结构、内部控制逻辑等内部结构,生成函数调用关系图、模块控制流图、内部文件调用关系图、子程序表、宏和函数参数表等各类图形图标,可以清晰地标识整个软件系统的组成结构,使其便于阅读和理解,然后可以通过分析这些图标,检查软件有没有存在缺陷或错误。

其中函数调用关系图通过应用程序中各函数之间的调用关系展示了系统的结构。通过查看函数调用关系图,可以检查函数之间的调用关系是否符合要求,是否存在递归调用,函数的调用是否过深,有没有存在独立的没有被调用的函数。从而可以发现系统是否存在结构缺陷,发现哪些函数是重要的,哪些是次要的,需要使用什么级别的覆盖要求等。

  模块控制流图是与程序流程图相类似的,由许多节点和连接节点的边组成的一种图形,其中一个节点代表一条语句或数条语句,边代表节点间控制流向,它显示了一个函数的内部逻辑结构。模块控制流图可以直观地反映出一个函数的内部逻辑结构,通过检查这些模块控制流图,能够很快发现软件的错误与缺陷。

检查项:代码风格和规则审核;程序设计和结构的审核;业务逻辑的审核;走查、审查与技术复审手册。

 

 

 

静态质量度量法

1、度量规则

  度量规则使用了代码行数、注释频度等参数度量软件的各种行为属性。

2、分类标准

  软件的可维护性采用以下四个分类标准来评估:可分析性(ANALYZABILITY)、可修改性(CHANGEABILITY)、稳定性(STABILITY)、可测性(TESTABILITY)。每个分类标准由一系列度量规则组成,各个规则分配一个权重,由规则的取值与权重值计算出每个分类标准的取值。

  function_TESTABILITY_DRCT_CALLS+LEVL+PATH+PARA

3、质量因素

  质量因素的取值与分类标准的计算方式类似:依据各分类标准取值组合权重方法计算。

  function_MAINTAINABILITY=function_ANALYZABILITY + function_CHANGEABILITY + function_ATABILITY + function_TESTABILITY

质量度量模型(从上到下)

质量因素(Factors):与分类标准的计算方式相似,依据各分类标准取值组合权重方法来计算,依据结果将软件质量分为四个等级,与分类标准等级内容相同。

分类标准(criteria):对某一软件质量分为不同的分类标准,每个分类标准由一系列度量规则组成,每个规则分配一个权重,每个分类标准的取值由规则的取值与权重值计算得出,依据结果将软件质量分为四个等级:

优秀(exceent):符合本模型框架中的所有规则(可以接受)

良好(good):未大量偏离模型框架中的规则(可以接受)

一般(fair):违背了模型框架中的大量规则(可以接受)

较差(poor):无法保障正常的软件可维护性(不可以接受)

度量规则(Metrics):使用代码行数、注释频度等参数度量软件各种行为属性

逻辑覆盖

逻辑覆盖是以程序内部的逻辑结构为基础的设计测试用例的技术。其中逻辑覆盖包括语句覆盖、判定覆盖、条件覆盖、判定条件组合覆盖、条件组合覆盖和路径覆盖。六种覆盖标准发现错误的能力呈由弱到强的变化:

1.语句覆盖每条语句至少执行一次。

2.判定覆盖每个判定的每个分支至少执行一次。

3.条件覆盖每个判定的每个条件应取到各种可能的值。

4.判定/条件覆盖同时满足判定覆盖和条件覆盖。

5.条件组合覆盖每个判定中各条件的每一种组合至少出现一次。

6.路径覆盖使程序中每一条可能的路径至少执行一次。

 

 

逻辑覆盖原则

 

语句覆盖

定义

“语句覆盖”是一个比较弱的测试标准,它的含义是:在测试时,首先设计若干个测试用例,然后运行被测程序, 使程序中的每个可执行语句至少执行一次。这时所谓“若干个”,自然是越少越好。即用最少得测试用例来达到语句全覆盖。

用例设计

为使程序中每个语句至少执行一次,只需设计一个能通过路径ace的例子就可以了,例如选择输入数据为: A=2,B=0,X=4 

这样该程序段的4个语句均得到执行,从而作到了语句覆盖。

 

优点

可以很直观地从源代码得到测试用例,无须细分每条判定表达式。

缺点

由于这种测试方法仅仅针对程序逻辑中显式存在的语句(即可执行语句),但对于隐藏的条件和可能到达的隐式逻辑分支,是无法测试的。

判定覆盖

定义

比“语句覆盖”稍强的覆盖标准是“判定覆盖”(或称branch coverage分支覆盖)标准。判定覆盖准则进行测试是指,设计若干测试用例,运行被测程序,使得程序中每个判断的取真分支和取假分支至少经历一次,即判断的真假值均曾被满足。判定覆盖又称为分支覆盖。设计测试用例只需要用最少条数,以判定条件结果为全真或者全假的思路来编写测试用例。

用例设计

如果设计两个例子,使它们能通过路径ace和abd,或者通过路径acd和abe,就可达到“判定覆盖”标准,为此,可以选择输入数据为: 
①A=2,B=0,X=4(沿判定条件结果为全真路径ace执行)

②A=1,B=1,X=1(沿判定条件结果为全假路径abd执行) 

 

优点

判定覆盖比语句覆盖要多几乎一倍的测试路径,当然也就具有比语句覆盖更强的测试能力。同样判定覆盖也具有和语句覆盖一样的简单性,无须细分每个判定就可以得到测试用例。

缺点

往往大部分的判定语句是由多个逻辑条件组合而成(如,判定语句中包含AND、OR、CASE),若仅仅判断其整个最终结果,而忽略每个条件的取值情况,必然会遗漏部分测试路径。

条件覆盖

定义

条件覆盖于分支覆盖不同,条件覆盖要求所设计的测试用例能使每个判定中的每一个条件都获得可能的取值,即每个条件至少有一次真值、有一次假值。

用例设计

A>1、B=0、A=2、X>1

为了达到“条件覆盖”标准,需要执行足够的测试用例使得在判定条件1处有:  

A>1、A≤1、B=0、B≠0

等各种结果出现,以及在判定条件2处有:A=2、A≠2、X>1、X≤1等各种结果出现。

现在只需设计以下两个测试用例就可满足这一标准:

①  A=2,B=0,X=4(沿判定条件中的各个条件都为真路径ace执行);

②  A=1,B=1,X=1(沿判定条件中的各个条件都为假路径abd执行) 

 

优点

增加了对条件判定情况的测试,增加了测试路径。

缺点

条件覆盖不一定包含判定覆盖。条件覆盖只能保证每个条件至少有一次为真,而不考虑所有的判定结果。

判定条件组合覆盖

定义

执行足够的测试用例,使得判定中每个条件取到各种可能的值,并使每个判定取到各种可能的结果。

用例设计

A>1、B=0、A=2、X>1

为了达到“条件覆盖”标准,需要执行足够的测试用例使得在判定条件1处有:  

A>1、A≤1、B=0、B≠0

等各种结果出现,以及在判定条件2处有:A=2、A≠2、X>1、X≤1等各种结果出现。

另外也要满足判定条件1处结果出现一次真和一次假,则要保证(A>1 AND B=0)为真(A=2,B=0)和为假(A=1,B=1),同时也满足了条件覆盖说的每个条件都要出现一次真和一次假。(A=2为真,B=0为真)和为假(A=1为假,B=1为假)。

同理判定条件2处结果出现一次真和一次假,则要保证(A=2 OR X>1)为真(A=2,X=4)和为假(A=1,X=1),同时也满足了条件覆盖说的每个条件都要出现一次真和一次假。(A=2为真,X=4为真)和为假(A=1为假,X=1为假)。

现在只需设计以下两个测试用例就可满足这一标准:

①  A=2,B=0,X=4(沿判定条件中的各个条件都为真,同时也满足判定条件结果均为真路径ace执行);

②  A=1,B=1,X=1(沿判定条件中的各个条件都为假,同时也满足判定条件结果均为假路径abd执行) 

 

优点

能同时满足判定、条件两种覆盖标准。

缺点

判定/条件覆盖准则的缺点是未考虑条件的组合情况。

条件组合覆盖

定义

执行足够的例子,使得每个判定中条件的各种可能组合都至少出现一次。显然,满足“条件组合覆盖”的测试用例是一定满足“判定覆盖”、“条件覆盖”和“判定/条件覆盖”的。

用例设计

 

条件组合覆盖说的判定条件里的每个条件组合在一起形成的各种可能。

使得下面8种条件组合都能够出现:

1)A>1, B=0    2)A>1, B≠0     3)A≤1, B=0    4)A≤1, B≠0   

5)A=2, X>1    6)A=2, X≤1     7)A≠2, X>1    8)A≠2, X≤1

判定条件1里有2个条件,所以条件组合的情况是2*2=4个的情况;排列组合里的组合逻辑形成的个数。如果有3个条件,则就有2*2*2=8个的情况,以此类推。

判定条件1:(A=2为真,B=0为真)、(A=2为真,B=1为假)、(A=1为假,B=0为真)、(A=1为假,B=1为假)。

判定条件2:(A=2为真,X=4为真)、(A=2为真,X=1为假)、(A=1为假,X=4为真)、(A=1为假,X=1为假)。

现在只需设计以下两个测试用例就可满足这一标准:

①  A=2,B=0,X=4(沿判定条件中的各个条件A=2为真,B=0为真,A=2为真,X=4为真,路径ace执行);

②  A=2,B=1,X=1(沿判定条件中的各个条件A=2为真,B=1为假,A=2为真,X=1为假,路径abe执行);

③  A=1,B=0,X=2(沿判定条件中的各个条件A=1为假,B=0为真,A=1为假,X=2为真,路径abe执行);

④  A=1,B=1,X=1(沿判定条件中的各个条件A=1为假,B=1为假,A=1为假,X=1为假,路径abd执行) 

上面四个例子虽然满足条件组合覆盖,但并不能覆盖程序中的每一条路径,例如路径acd就没有执行,因此,条件组合覆盖标准仍然是不彻底。

优点

能同时满足判定、条件两种覆盖标准。条件组合覆盖准则满足判定覆盖、条件覆盖和判定/条件覆盖准则。

缺点

线性地增加了测试用例的数量。

路径覆盖

定义

选取足够多的测试数据,使程序的每条可能路径都至少执行一次(如果程序图中有环,则要求每个环至少经过一次)。

对于比较简单的小程序来说,实现路径覆盖是可能的,但是如果程序中出现了多个判断和多个循环,可能的路径数目将会急剧增长,以致实现路径覆盖是几乎不可能的。

所以我们需要路径分析,计算程序中的路径数(复杂度)。

以下的公式:V(G)=e-n+2

PS:其中e为边数,n为结点数。

优点

这种测试方法可以对程序进行彻底的测试,比前面五种的覆盖面都广。

缺点

需要设计大量、复杂的测试用例,使得工作量呈指数级增长,不见得把所有的条件组合都覆盖。

基本路径测试法

在程序控制图的基础上,通过分析控制构造的环行复杂性,导出基本可执行路径集合,从而设计测试用例。设计出的测试用例要保证在测试中程序的每一个基本独立路径至少执行一次。

在程序控制流图的基础上,通过分析控制构造的环路复杂性,导出基本可执行路径集合,从而设计测试用例。

包括以下4 个步骤

1. 程序的控制流图:描述程序控制流的一种图示方法。

2. 程序圈复杂度:McCabe复杂性度量。从程序的环路复杂性可导出程序基本路径集合中的独立路径条数,这是确定程序中每个可执行语句至少执行一次所必须的测试用例数目的上界。

3. 导出测试用例:根据圈复杂度和程序结构设计用例数据输入和预期结果。

4. 准备测试用例:确保基本路径集中的每一条路径的执行。

一个工具方法: 

图形矩阵:是在基本路径测试中起辅助作用的软件工具,利用它可以实现自动地确定一个基本路径集。

另外,对于测试用例的选择除了满足所选择的覆盖程度(或覆盖标准)外还需要尽可能的采用边界值分析法、错误推测法等常用地设计方法。采用边界值分析法设计合理的输入条件与不合理的输入条件;条件边界测试用例应该包括输入参数的边界与条件边界(if,while,for,switch ,SQL Where子句等)。错误推测法,列举出程序中所有可能的错误和容易发生错误的特殊情况,根据它们选择测试用例;在编码、单元测试阶段可以发现很多常见的错误和疑似错误,对于这些错误应该作重点测试,并设计相应的测试用例。

控制流图

基本语句对应的控制流图:

 

程序流程图->控制流图

 

如何根据程序流程图画出控制流程图?

  在将程序流程图简化成控制流图时,应注意:

  1)在选择或多分支结构中,分支的汇聚处应有一个汇聚结点。

  2)边和结点圈定的范围叫做区域,当对区域计数时,图形外的区域也应记为一个区域。

如下图所示:

三种计算方法:

1. 控制流图中区域的数量

2. V(G)= E-N+2,E是边数,N是结点数

3. V(G)= P+1,P是判定结点的数量

圆圈称为控制流图的一个结点,表示一个或多个无分支的语句或源程序语句

独立路径( 基本路径)

一条程序执行的路径 ,至少包含一条在定义该路径之前的其他基本路径中所不曾用过的边( 即:至少引入程序的一个新处理语句集合或一个新条件)

注意:独立路径不应该经过同一个判定结点的左右两侧,否则这条路径如果出现错误,则不知道是哪一侧出现错误。

设计测试用例步骤 

第一步:画出控制流图

  流程图用来描述程序控制结构。可将流程图映射到一个相应的流图(假设流程图的菱形决定框中不包含复合条件)。在流图中,每一个圆,称为流图的结点,代表一个或多个语句。一个处理方框序列和一个菱形决策框可被映射为一个结点,流图中的箭头,称为边或连接,代表控制流,类似于流程图中的箭头。一条边必须终止于一个结点,即使该结点并不代表任何语句(例如:if-else-then结构)。由边和结点限定的范围称为区域。计算区域时应包括图外部的范围。

画出其程序流程图和对应的控制流图如下

       

第二步:计算圈复杂度

  圈复杂度是一种为程序逻辑复杂性提供定量测度的软件度量,将该度量用于计算程序的基本的独立路径数目,为确保所有语句至少执行一次的测试数量的上界。独立路径必须包含一条在定义之前不曾用到的边。

  有以下三种方法计算圈复杂度:

  流图中区域的数量对应于环型的复杂性;

  给定流图G的圈复杂度V(G),定义为V(G)=E-N+2,E是流图中边的数量,N是流图中结点的数量;

  给定流图G的圈复杂度V(G),定义为V(G)=P+1,P是控制流图G中判定结点的数量。

  

第三步:导出测试用例

  根据上面的计算方法,可得出四个独立的路径。(一条独立路径是指和其他的独立路径相比,至少引入一个新处理语句或一个新判断的程序通路。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

  根据上面的独立路径,去设计输入数据,使程序分别执行到上面四条路径。

第四步:准备测试用例

  为了确保基本路径集中的每一条路径的执行,根据判断结点给出的条件,选择适当的数据以保证某一条路径可以被测试到,满足上面例子基本路径集的测试用例是:

工具方法:图形矩阵

导出控制流图和决定基本测试路径的过程均需要机械化,为了开发辅助基本路径测试的软件工具,称为图形矩阵(graph matrix)的数据结构很有用。利用图形矩阵可以实现自动地确定一个基本路径集。一个图形矩阵是一个方阵,其行/列数控制流图中的结点数,每行和每列依次对应到一个被标识的结点,矩阵元素对应到结点间的连接(即边)。

对每个矩阵项加入连接权值(link  weight),图矩阵就可以用于在测试中评估程序的控制结构,连接权值为控制流提供了另外的信息。最简单情况下,连接权值是 1(存在连接)或0(不存在连接),但是,连接权值可以赋予更有趣的属性:

执行连接(边)的概率。

穿越连接的处理时间。

穿越连接时所需的内存。

穿越连接时所需的资源。

上图为图形矩阵:

连接权为“1”表示存在一个连接,在图中如果一行有两个或更多的元素“1”,则这行所代表的结点一定是一个判定结点,通过连接矩阵中有两个以上(包括两个)元素为“1”的个数,就可以得到确定该图圈复杂度的另一种算法。

循环测试

     从本质上来说,循环测试的目的就是检查循环结构的有效性。

四种循环 :简单循环 、嵌套循环 、串接循环、无结构循环(非结构循环)

简单循环

对于简单循环,测试应包括以下几种,其中的n 表示循环允许的最大次数。

1.零次循环:从循环入口直接跳到循环出口。 (换句话说:跳过循环)

2. 一次循环:查找循环初始值方面的错误。

3. 二次循环:检查在多次循环时才能暴露的错误。

4. m次循环:此时的m<n-1(通常取m=n/2),也是检查在多次循环时才能暴露的错误。

5. n(最大)次数循环、n+1(比最大次数多一)次的循环、n-1(比最大次数少一)次的循环。

嵌套循环

1.从最内层循环开始,设置所有其他层的循环为最小值;

2.对最内层循环使用简单循环的全部测试。测试时保持所有外层循环的循环变量(迭代参数)为最小值。另外,对越界值和非法值增加一些额外的测试。

3.逐步外推,对其外面一层循环进行测试。测试时保持所有外层循环的循环变量取最小值,所有其它嵌套内层循环的循环变量取“典型”值。

4.反复进行,直到所有各层循环测试完毕。

5.对全部各层循环同时取最小循环次数,或者同时取最大循环次数。对于后一种测试,由于测试量太大,需人为指定最大循环次数。

举例说明

1 案例描述 

昨天去面试,面试官出了一道面试题目,但是知道一个初步的优化,但不知道为什么会有性能提高,下去上网才恍然大悟:

题目是这样的:请对以下的代码进行优化 

Java代码  

for (int i = 0; i < 1000; i++)  

    for (int j = 0; j < 100; j++)  

        for (int k = 0; k < 10; k++)  

            testFunction (i, j, k);  

(注:为了同后面的内容一致,这里对原题目进行了部分修改) 
2 案例分析 

从给出的代码可知,不论如何优化,testFunction执行的次数都是相同的,该部分不存在优化的可能。那么,代码的优化只能从循环变量i、j、k的实例化、初始化、比较、自增等方面的耗时上进行分析。 
首先,我们先分析原题代码循环变量在实例化、初始化、比较、自增等方面的耗时情况:

变量

实例化(次数)

初始化(次数)

比较(次数)

自增(次数)

i

1

1

1000

1000

j

1000

1000

1000 * 100

1000 * 100

k

1000 * 100

1000 * 100

1000 * 100 * 10

1000 * 100 * 10

(注:由于单次耗时视不同机器配置而不同,上表相关耗时采用处理的次数进行说明) 
该代码的性能优化就是尽可能减少循环变量i、j、k的实例化、初始化、比较、自增的次数,同时,不能引进其它可能的运算耗时。 
3 解决过程 
从案例分析,对于原题代码,我们提出有两种优化方案: 
3.1 优化方案一 
代码如下: 

Java代码  

for (int i = 0; i < 10; i++)  

    for (int j = 0; j < 100; j++)  

        for (int k = 0; k < 1000; k++)  

            testFunction (k, j, i);  

该方案主要是将循环次数最少的放到外面,循环次数最多的放里面,这样可以最大程度的(注:3个不同次数的循环变量共有6种排列组合情况,此种组合为最优)减少相关循环变量的实例化次数、初始化次数、比较次数、自增次数,方案耗时情况如下: 

变量

实例化(次数)

初始化(次数)

比较(次数)

自增(次数)

i

1

1

10

10

j

10

10

10 * 100

10 * 100

k

10 * 100

10 * 100

10 * 100 * 1000

10 * 100 * 1000

3.2 优化方案二 
代码如下: 

Java代码  

int i, j, k;  

for (i = 0; i < 10; i++)  

    for (j = 0; j < 100; j++)  

        for (k = 0; k < 1000; k++)  

            testFunction (k, j, i);  

该方案在方案一的基础上,将循环变量的实例化放到循环外,这样可以进一步减少相关循环变量的实例化次数,方案耗时情况如下: 

变量

实例化(次数)

初始化(次数)

比较(次数)

自增(次数)

i

1

1

10

10

j

1

10

10 * 100

10 * 100

k

1

10 * 100

10 * 100 * 1000

10 * 100 * 1000

4 解决结果 
那么,提出的优化方案是否如我们分析的那样有了性能上的提升了呢?我们编写一些测试代码进行验证,数据更能说明我们的优化效果。 
4.1 测试代码 

Java代码  

public static void testFunction(int i, int j, int k) {  

        System.out.print("");   // 注:该方法不影响整体优化,这里只有简单输出  

    }  

     public static void testA() {  

        long start = System.nanoTime();  

        for (int i = 0; i < 1000; i++)  

            for (int j = 0; j < 100; j++)  

                for (int k = 0; k < 10; k++)  

                    testFunction(i, j, k);  

        System.out.println("testA time>>" + (System.nanoTime() - start));  

    }  

      public static void testB() {  

        long start = System.nanoTime();  

        for (int i = 0; i < 10; i++)  

            for (int j = 0; j < 100; j++)  

                for (int k = 0; k < 1000; k++)  

                    testFunction(k, j, i);  

        System.out.println("testB time>>" + (System.nanoTime() - start));  

    }  

      public static void testC() {  

        long start = System.nanoTime();  

        int i;  

        int j;  

        int k;  

        for (i = 0; i < 10; i++)  

            for (j = 0; j < 100; j++)  

                for (k = 0; k < 1000; k++)  

                    testFunction(k, j, i);  

        System.out.println("testC time>>" + (System.nanoTime() - start));  

}  

4.2 测试结果 
1、测试机器配置:Pentium(R) Dual-Core CPU E5400 @2.70GHz 2.70GHz, 2GB内存; 
2、循环变量i、j、k循环次数分别为10、100、1000,进行5组测试,测试结果如下: 

第1组

第2组

第3组

第4组

第5组

原方案

171846271

173250166

173910870

173199875

173725328

方案一

168839312

168466660

168372616

168310190

168041251

方案二

168001838

169141906

168230655

169421766

168240748

从上面的测试结果来看,优化后的方案明显性能优于原方案,达到了优化的效果。但优化方案二并没有如我们预期的优于方案一,其中第2、4、5组的数据更是比方案一差,怀疑可能是循环次数太少,以及测试环境相关因素影响下出现的结果。 
3、重新调整循环变量i、j、k循环次数分别为20、200、2000,进行5组测试,测试结果如下: 

第1组

第2组

第3组

第4组

第5组

原方案

1355397203

1358978176

1358128281

1350193682

1354786598

方案一

1343482704

1348410388

1343978037

1347919156

1340697793

方案二

1342427528

1343897887

1342662462

1342124048

1336266453

从上面的测试结果来看,优化后的方案基本符合我们的预期结果。 
5 总结 
从案例分析和解决过程中的三个表的分析可知,优化方案一和优化方案二的性能都比原代码的性能好,其中优化方案二的性能是最好的。在嵌套For循环中,将循环次数多的循环放在内侧,循环次数少的循环放在外侧,其性能会提高;减少循环变量的实例化,其性能也会提高。从测试数据可知,对于两种优化方案,如果在循环次数较少的情况下,其运行效果区别不大;但在循环次数较多的情况下,其效果就比较明显了。

串接循环

对于串接循环,要区别两种情况。

1.如果各个循环互相独立,则串接循环可以用与简单循环相同的方法进行测试。

2.如果有两个循环处于串接状态,而前一个循环的循环变量的值是后一个循环的初值。则这几个循环不是互相独立的,则需要使用测试嵌套循环的办法来处理。

 

对于非结构循环,不能测试, 应重新设计循环结构,使之成为其它循环方式,然后再进行测试。

条件测试

条件测试方法注重于测试程序中的条件。是检查程序模块中所包含逻辑条件的测试用例设计方法。

条件

程序中的条件分为简单条件和复合条件。

简单条件是一个布尔变量或一个可能带有NOT(“!”)操作符的关系表达式。关系表达式的形式如:

E1<关系操作符>E2

其中E1和E2是算术表达式,而<关系操作符>是下列之一:“<”、“≤”、“=”、“≠”(“!=”)、“>”、或“≥”。

复合条件由简单条件通过逻辑运算符(AND、OR、NOT)和括号连接而成,不含关系表达式的条件称为布尔表达式。

所以条件的成分类型包括:布尔操作符、布尔变量、布尔括弧(括住简单或复杂条件)、关系操作符、算术表达式。

条件测试的目的

条件测试是测试程序条件错误和程序的其他错误。如果程序的测试集能够有效地检测程序中的条件错误,则该测试集可能也会有效地检测程序中的其他错误。此外,如果测试策略对检测条件错误有效,则它也可能有效地检测程序错误。

条件测试策略

1) 穷举测试(条件组合)

有n个变量的布尔表达式需要2n个可能的测试(n>0)。这种策略可以发现布尔操作符、变量和括弧的错误,但是只有在n很小时实用。

2) 分支测试

分支测试可能是最简单的条件测试策略,它是真假分支必须至少执行一次的路径策略,对于复合条件C,C的真分支和假分支以及C中的每个简单条件都需要至少执行一次。

域测试是对于大于、小于和等于的值的测试路径策略。域测试要求从有理表达式中导出三个或四个测试,有理表达式的形式如:

E1<关系操作符>E2

需要三个测试分别用于计算E1的值是大于、等于或小于E2的值。如果<关系操作符>错误,而E1和E2正确,则这三个测试能够发现关系算式的错误。为了发现E1和E2的错误,计算E1小于或大于E2的测试应使两个值间的差别尽可能小。

3) BRO(branch and relational) 测试

如果在一个判定的复合条件表达式中每个布尔变量和关系运算符最多只出现一次,而且没有公共变量,应用一种称之为BRO(分支与关系运算符)的测试法可以发现多个布尔运算符或关系运算符错,以及其他错误。

BRO策略引入条件约束的概念。设有n个简单条件的复合条件C,其条件约束为D= (D1,D2,…,Dn) ,其中Di(0<i≤n)是条件C中第i个简单条件的输出约束。如果在C的执行过程中,其每个简单条件的输出都满足D中对应的约束,则称条件C的条件约束D由C的执行所覆盖。对于布尔变量或布尔表达式B,B的输出约束必须是真(t)或假(f);对于关系表达式,其输出约束为符号>、=、< 。

域测试

 

 

由于程序中每条路径对应着一个输入域,是程序的一个子计算。如果程序的控制流有错误,则对某一特定的输入可能执行的是一条错误路径,这种错误被称为路径错误或域错误。

而域测试主要是针对域错误进行的测试。

域测试的基本步骤如下:

(1):根据各个分支谓词,给出子域的分割图;

(2):对每个子域的边界,采用ON-OFF-ON原则选取测试点。

(3):在子域内选取一些测试点。

(4):针对这些测试点进行测试。

符号测试

Z路径覆盖测试

 

实施步骤

1.测试计划阶段:根据需求说明书,制定测试进度。

2.测试设计阶段:依据程序设计说明书,按照一定规范化的方法进行软件结构划分和设计测试用例。

3.测试执行阶段:输入测试用例,得到测试结果。

4.测试总结阶段:对比测试的结果和代码的预期结果,分析错误原因,找到并解决错误。

优缺点
优点

1.迫使测试人员去仔细思考软件的实现

2.可以检测代码中的每条分支和路径

3.揭示隐藏在代码中的错误

4.对代码的测试比较彻底

5.最优化

缺点

1.代价有些高,需要测试人员有编程能力

2.无法检测代码中遗漏的路径和数据敏感性错误

3.不能直接验证需求的正确性

局限

即使每条路径都测试了仍然可能有错误。可能出现的情况如下:

穷举路径测试决不能查出程序违反了设计规范,即程序本身是个错误的程序。

穷举路径测试不可能查出程序中因遗漏路径而出错。

穷举路径测试可能发现不了一些与数据相关的错误。

3.灰盒测试(Gray-Box Testing)

灰盒测试是介于白盒测试和黑盒测试之间的一种,灰盒测试多用于集成测试阶段,不仅关注输入、输出的正确性,同时也关注程序内部的情况。灰盒测试不像白盒测试那样详细、完整,但又比黑盒测试更关注程序的内部逻辑,常常是通过一些表征性的现象、事件、标志来判断内部的运行状态。有时候输出是正确的,但内部其实已经错误了,这种情况非常多,如果每次都通过白盒测试来操作,效率会很低,因此需要采取这样的一种灰盒的方法。

灰盒测试:功能+接口

定义

灰盒测试由方法和工具组成,这些方法和工具取材于应用程序的内部知识和与之交互的环境,能够用于黑盒测试以增强测试效率、错误发现和错误分析的效率。灰盒测试涉及输入和输出,但使用关于代码和程序操作等通常在测试人员视野之外的信息设计测试。

目的

一、确认软件的质量

二、提供信息,提供给开发人员或程序经理的反馈信息,为风险评估所准备的信息。

三、软件测试不仅是在测试软件产品的本身,而且还包括软件开发的过程。

测试任务

1、寻找Bug;

2、避免软件开发过程中的缺陷;

3、衡量软件的品质;

4、关注用户的需求。

如何做好灰盒测试?
  1. 测试定位要清晰。灰盒测试的对象应该是整个产品,而非各个组件,应从整个测试产品的业务出发进行测试设计。
  2. 测试阶段要正确。灰盒测试应该在集成测试中采用,他并不适合于单元测试。
  3. 测试辅助要必备。灰盒测试需要深入产品代码逻辑,对于测试人员来说,业务逻辑图是必不可少的,测试人员需要根据业务逻辑图进行功能点划分,并扩展用例。另外可以借助于测试覆盖率等工具辅助查找遗漏功能点。
  4. 运行状态检查点要仔细选择。灰盒测试对于程序运行状态的检查往往采用标志来判断,测试人员一定要仔细考虑,否则很容易遗漏某些bug。
做灰盒测试需要哪些条件呢?

1、需要在测试中,除了部署产品之外,还有就是程序源代码,不管外部是多少漂亮界面或易用的功能,最终都是由源代码来实现的。所以在部署时,要安装源代码。从源代码编译生成的目录中运行软件。
2、需要代码覆盖率工具的配置;部署可以针对本软件开发语言的代码覆盖率工具;
3、测试人员要具备阅读代码的能力,其对开发语言的熟悉程度和程序设计经验多少决定了采用灰盒测试能够取得多大的好处,所以配置这方面的测试人员或进行必要的培训是必要的。
那么有人可能问,服务器端软件适合做灰盒测试吗?回答是肯定的。任何一个项目都可以从灰盒测试中获得裨益。不管是手机中使用的各种嵌入式软件、还是web页面和服务器端的任何脚本,都可以运用这种测试方法。

优点

1、 能够进行基于需求的覆盖测试和基于程序路径覆盖的测试;
2、 测试结果可以对应到程序内部路径,便于bug的定位、分析和解决;
3、 能够保证设计的黑盒测试用例的完整性,防止遗漏软件的一些不常用的功能或功能组合;
4、 能够需求或设计不详细或不完整对测试造成的影响。

缺点

1、    投入的时间比黑盒测试大概多20-40%的时间;

2、    对测试人员的技术要求更高;

灰盒测试的好处

测试者可能知道系统组件之间是如何互相作用的,但缺乏对内部程序功能和运作的详细了解。对于内部过程,灰盒测试把程序看作一个必须从外面进行分析的黑盒。灰盒测试通常与web服务应用一起使用,因为尽管应用程序复杂多变,并不断发展进步,因特网仍可以提供相对稳定的接口。由于不需要测试者接触源代码,因此灰盒测试不存在侵略性和偏见。开发者和测试者间有明显的区别,人事冲突的风险减到最小。

灰盒测试相对于黑盒测试和白盒测试有什么特点?

1.灰盒测试比白盒测试效率高,从程序的整体出发,而非细节.
2.灰盒测试健壮性好,相对于白盒测试降低了程序代码改变而导致用例失效的风险。
3.灰盒测试更细致。灰盒测试要求测试人员关注程序的代码逻辑,根据代码逻辑扩充用例,更加细致。

原文地址:https://www.cnblogs.com/douyini/p/12899740.html