《软件编码和软件测试.ppt》由会员分享,可在线阅读,更多相关《软件编码和软件测试.ppt(175页珍藏版)》请在三一办公上搜索。
1、第4章 软件编码和软件测试,本章内容:l 结构化程序设计(程序设计语言的选择 程序设计风格)l 软件测试目标l 测试方法l 测试步骤l 设计测试方案l 测试原则和测试策略l 软件调试、验证与确认l 软件测试文档重点:l 程序设计风格l设计软件测试方案,4.1 结构化程序设计,结构化程序设计(Structured Programming,SP)仅采用顺序、选择、重复三种基本控制结构;每种基本结构只有一个入口、一个出口;将这三种基本控制结构根据程序的逻辑,嵌套或组合成结构化程序,完成预定的功能。结构化程序设计的特点源程序有清晰性,并能较好地适合自顶向下或自底向上的程序设计技术。在详细设计阶段,使系
2、统结构具有模块化和清晰性的特性。在软件编码阶段,使软件易于理解、修改,便于重复使用。,4.1.1 程序设计语言的选择,1.程序设计语言的分类(1)面向机器语言:机器语言和汇编语言。(2)高级程序设计语言2.高级语言选用的实用标准(1)项目的应用领域(2)软件开发环境(3)根据系统用户的要求来选择(4)软件开发人员的知识,4.1.2 程序设计风格,源程序文档编写规则1源程序文档编写时,其标识符名称、注解和程序布局等要合理。2.数据说明3.语句构造要简单直接4.输入输出语句5.程序效率程序设计主要应考虑的是程序的正确性、可理解性、可测试性和可维护性。,程序的注释夹在程序中的注释是程序员与日后的程序
3、读者之间通信的重要手段。注释决不是可有可无的。一些正规的程序文本中,注释行的数量占到整个源程序的13到12,甚至更多。注释分为序言性注释和功能性注释。序言性注释通常置于每个程序模块的开头部分,它应当给出程序的整体说明,对于理解程序本身具有引导作用。有些软件开发部门对序言性注释做了明确而严格的规定,要求程序编制者逐项列出。,有关项目包括:程序标题;有关本模块功能和目的的说明;主要算法;接口说明:包括调用形式,参数描述,子程序清单;有关数据描述:重要的变量及其用途,约束或限制条件,以及其它有关信息;模块位置:在哪一个源文件中,或隶属于哪一个软件包;开发简历:模块设计者,复审者,复审日期,修改日期及
4、有关说明等。,功能性注释功能性注释嵌在源程序体中,用以描述其后的语句或程序段是在做什么工作,或是执行了下面的语句会怎么样。而不要解释下面怎么做。例如,/*ADD AMOUNT TO TOTAL*/TOTAL=AMOUNTTOTAL 不好。如果注明把月销售额计入年度总额,便使读者理解了下面语句的意图:/*ADD MONTHLY-SALES TO ANNUAL-TOTAL*/TOTAL=AMOUNTTOTAL要点 描述一段程序,而不是每一个语句;用缩进和空行,使程序与注释容易区别;注释要正确。,语句结构 在设计阶段确定了软件的逻辑流结构,但构造单个语句则是编码阶段的任务。语句构造力求简单、直接,不
5、能为了片面追求效率而使语句复杂化。在一行内只写一条语句在一行内只写一条语句,并且采取适当的移行格式,使程序的逻辑和功能变得更加明确。许多程序设计语言允许在一行内写多个语句。但这种方式会使程序可读性变差。因而不可取。例如,有一段排序程序FOR I:=1 TO N1 DO BEGIN T:=I;FOR J:=I1 TO N DO IF AJAT THEN T:=J;IF TI THEN BEGIN WORK:=AT;AT:=AI;AI:=WORK;END END;由于一行中包括了多个语句,掩盖了程序的循环结构和条件结构,使其可读性变得很差。,FOR I:=1 TO N-1 DO/改进布局 BEGI
6、N T:=I;FOR J:=I1 TO N DO IF AJAT THEN T:=J;IF TI THEN BEGIN WORK:=AT;AT:=AI;AI:=WORK;END END;程序编写首先应当考虑清晰性程序编写首先应当考虑清晰性,不要刻意追求技巧性,使程序编写得过于紧凑。例如,有一个用 C 语句写出的程序段:AI=AIAT;AT=AIAT;AI=AIAT;,此段程序可能不易看懂,有时还需用实际数据试验一下。实际上,这段程序的功能就是交换AI和AT中的内容。目的是为了节省一个工作单元。如果改一下:WORK=AT;AT=AI;AI=WORK;就能让读者一目了然了。程序要能直截了当地说明程
7、序员的用意。程序编写得要简单,写清楚,直截了当地说明程序员的用意。例如,for(i=1;i=n;i+)for(j=1;j=n;j+)Vij(ij)*(ji)除法运算()在除数和被除数都是整型量时,其结果只取整数部分,而得到整型量。,当 ij 时,i/j=0 当 ji 时,j/i=0 得到的数组 当ij时 Vij=(ij)*(ji)=0 当ij时 Vij=(ij)*(ji)=1这样得到的结果 V 是一个单位矩阵。写成以下的形式,就能让读者直接了解程序编写者的意图。for(i1;i=n;i+)for(j1;j=n;j+)if(i=j)Vij 1.0;else Vij 0.0;,除非对效率有特殊的要
8、求,程序编写要做到清晰第一,效率第二。不要为了追求效率而丧失了清晰性。事实上,程序效率的提高主要应通过选择高效的算法来实现。,编程标准及开发规范,系统环境规范包括硬件、系统软件(操作系统、汉字操作系统、网络操作系统、数据库等)、开发工具及有关工具软件等内容。,硬件规范:服务器:CPU:Pentium以上;内存128M,显示卡8M,硬盘空间:建议2G剩余空间以上。客户机:CPU:Pentium以上,内存64M,显示卡8M,硬盘空间至少200M剩余空间以上,打印机为任何PC机兼容针式、喷墨、激光打印机均可。系统软件规范:服务器操作系统:MS Windows Server 4.0 或/MS Wind
9、ows 2000 Server简体中文版数据库:MS SQL Server 7.0客户机操作系统:MS Windows 95/98/2000简体中文版系统开发软件:Sybase Power Builder7.0数据库设计软件:Sybase Power Designer 6.1.2 32-bit,4.2 软件测试目标,()软件测试是为了发现程序中的错误而执行程序的过程;()好的测试方案能够发现尚未发现的错误;()成功的测试是发现了尚未发现的错误的测试。软件测试的目的是,通过人工或计算机执行程序来有意识地发现程序中的设计错误和编码错误。,4.3 软件测试方法,4.3.1 静态分析与动态测试1.静态
10、分析2.动态测试:以执行程序并分析程序来查错。为了进行软件测试,需要预先准备好两种数据:输入数据;预期的输出结果。我们把以发现错误为目标的用于软件测试的输入数据及与之对应的预期输出结果叫测试用例。4.3.2 黑盒法与白盒法1.黑盒法(Black.Box Testing)又称功能测试,其测试用例完全是根据程序的功能说明来设计的。2.白盒法(White Box Testing)又称结构测试,其测试用例是根据程序内部的逻辑结构和执行路径来设计的。常把黑盒法和白盒法联合起来进行,这也称为灰盒法。,4.4 软件测试步骤,4.4.1 模块测试也称单元测试,其目的是检查每个模块是否能独立、正确地运行。模块测
11、试通常在程序设计时进行。驱动程序代替主程序,用来测试子程序。存根程序也称“虚拟子程序”,测试主模块。4.4.2 集成测试子系统的组装称为集成化。集成测试分为子系统测试和系统测试两种。渐增式测试、非渐增式测试1、自顶向下集成2、自底向上集成4.4.3 程序审查会和人工运行4.4.4 确认测试1.确认测试必须有用户积极参与,或以用户为主进行。2.软件配置复审3.Alpha测试和Beta测试4.4.5 平行运行,一次性组装方式(big bang)它是一种非增殖式组装方式。也叫做整体拼装。使用这种方式,首先对每个模块分别进行模块测试,然后再把所有模块组装在一起进行测试,最终得到要求的软件系统。,增殖式
12、组装方式这种组装方式又称渐增式组装首先对一个个模块进行模块测试,然后将这些模块逐步组装成较大的系统在组装的过程中边连接边测试,以发现连接过程中产生的问题通过增殖逐步组装成为要求的软件系统。自顶向下的增殖方式这种组装方式将模块按系统程序结构,沿控制层次自顶向下进行组装。自顶向下的增殖方式在测试过程中较早地验证了主要的控制和判断点。选用按深度方向组装的方式,可以首先实现和验证一个完整的软件功能。,自底向上的增殖方式这种组装的方式是从程序模块结构的最底层的模块开始组装和测试。因为模块是自底向上进行组装,对于一个给定层次的模块,它的子模块(包括子模块的所有下属模块)已经组装并测试完成,所以不再需要桩模
13、块。在模块的测试过程中需要从子模块得到的信息可以直接运行子模块得到。,自顶向下增殖的方式和自底向上增殖的方式各有优缺点。一般来讲,一种方式的优点是另一种方式的缺点。混合增殖式测试衍变的自顶向下的增殖测试 首先对输入输出模块和引入新算法模块进行测试;再自底向上组装成为功能相当完整且相对独立的子系统;然后由主模块开始自顶向下进行增殖测试。自底向上自顶向下的增殖测试 首先对含读操作的子系统自底向上直至根结点模块进行组装和测试;然后对含写操作的子系统做自顶向下的组装与测试。,测试技术1、黑盒测试(功能测试或数据驱动测试)把测试对象看做一个黑盒子,测试人员完全不考虑程序内部的逻辑结构和内部特性,只依据程
14、序的需求规格说明书,检查程序的功能是否符合它的功能说明。黑盒测试方法是在程序接口上进行测试,主要是为了发现以下错误:是否有不正确或遗漏了的功能?在接口上,输入能否正确地接受?能否输出正确的结果?是否有数据结构错误或外部信息(例如数据文件)访问错误?性能上是否能够满足要求?是否有初始化或终止性错误?,用黑盒测试发现程序中的错误,必须在所有可能的输入条件和输出条件中确定测试数据,来检查程序是否都能产生正确的输出。但这是不可能的。假设一个程序P有输入量X和Y及输出量Z。在字长为32位的计算机上运行。若X、Y取整数,按黑盒方法进行穷举测试:可能采用的测试数据组:232232 264 如果测试一组数据需
15、要1毫秒,一年工作365 24小时,完成所有测试需5亿年。,2、白盒测试(结构测试或逻辑驱动测试)把测试对象看做一个透明的盒子,它允许测试人员利用程序内部的逻辑结构及有关信息,设计或选择测试用例,对程序所有逻辑路径进行测试。通过在不同点检查程序的状态,确定实际的状态是否与预期的状态一致。白盒测试主要想对程序模块进行如下的检查:对程序模块的所有独立的执行路径至少测试一次;对所有的逻辑判定,取“真”与取“假”的两种情况都至少测试一次;在循环的边界和运行界限内执行循环体;测试内部数据结构的有效性,等。,对一个具有多重选择和循环嵌套的程序,不同的路径数目可能是天文数字。给出一个小程序的流程图,它包括了
16、一个执行20次的循环。包含的不同执行路径数达520条,对每一条路径进行测试需要1毫秒,假定一年工作365 24小时,要想把所有路径测试完,需3170年。,逻辑覆盖法,根据覆盖目标的不同,逻辑覆盖又可分为语句覆盖、判定覆盖、条件覆盖、判定/条件覆盖、组合覆盖和路径覆盖。语句覆盖:选择足够多的测试用例,使得程序中的每个可执行语句至少执行一次。判定覆盖:通过执行足够的测试用例,使得程序中的每个判定至少都获得一次“真”值和“假”值,也就是使程序中的每个取“真”分支和取“假”分支至少均经历一次,也称为“分支覆盖”。条件覆盖:设计足够多的测试用例,使得程序中每个判定包含的每个条件的可能取值(真/假)都至少
17、满足一次。,逻辑覆盖法(续),判定/条件覆盖:设计足够多的测试用例,使得程序中每个判定包含的每个条件的所有情况(真/假)至少出现一次,并且每个判定本身的判定结果(真/假)也至少出现一次。满足判定/条件覆盖的测试用例一定同时满足判定覆盖和条件覆盖。组合覆盖:通过执行足够的测试用例,使得程序中每个判定的所有可能的条件取值组合都至少出现一次。满足组合覆盖的测试用例一定满足判定覆盖、条件覆盖和判定/条件覆盖。路径覆盖:设计足够多的测试用例,要求覆盖程序中所有可能的路径。,逻辑覆盖法(续),逻辑覆盖法(续),void DoWork(int x,int y,int z)1 int k=0,j=0;2 if
18、(x3)/语句块310,逻辑覆盖法(续),2,7,9,4 5,8,语句覆盖,要实现DoWork函数的语句覆盖,只需设计一个测试用例就可以覆盖程序中的所有可执行语句。只要通过路径abd(或流图中2-45-7-8-9)就可以语句覆盖。测试用例输入为:x=4、y=5、z=5 程序执行的路径是:abd分析:语句覆盖可以保证程序中的每个语句都得到执行,但发现不了判定中逻辑运算的错误,即它并不是一种充分的检验方法。例如在第一个判定(x3)&(z10)中把“&”错误的写成了“|”,这时仍使用该测试用例,则程序仍会按照流程图上的路径abd执行。可以说语句覆盖是最弱的逻辑覆盖准则。,判定覆盖,要实现DoWork
19、函数的判定覆盖,需要设计两个测试用例。测试用例的输入为:x=4、y=5、z=5;x=2、y=5、z=5程序执行的路径分别是:abd;ace使用acd、abe两条路径的用例也满足判定覆盖分析:上述两个测试用例不仅满足了判定覆盖,同时还做到语句覆盖。从这点看似乎判定覆盖比语句覆盖更强一些,但仍然无法确定判定内部条件的错误。例如把第二个判定中的条件y5错误写为y5,使用上述测试用例,照样能按原路径执行而不影响结果。因此,需要有更强的逻辑覆盖准则去检验判定内的条件。,判定覆盖(续),说明:以上仅考虑了两出口的判断,我们还应把判定覆盖准则扩充到多出口判断(如Case语句)的情况。因此,判定覆盖更为广泛的
20、含义应该是使得每一个判定获得每一种可能的结果至少一次。,条件覆盖,在实际程序代码中,一个判定中通常都包含若干条件。条件覆盖的目的是设计若干测试用例,在执行被测程序后,要使每个判定中每个条件的可能值至少满足一次。对DoWork函数的各个判定的各种条件取值加以标记。对于第一个判定(x3)&(z3 取真值记为T1,取假值记为-T1 条件z5):条件x=4 取真值记为T3,取假值记为-T3 条件y5 取真值记为T4,取假值记为-T4,条件覆盖(续),根据条件覆盖的基本思想,要使上述4个条件可能产生的8种情况至少满足一次,设计测试用例如下:,分析:上面这组测试用例不但覆盖了4个条件的全部8种情况,而且将
21、两个判定的4个分支b、c、d、e也同时覆盖了,即同时达到了条件覆盖和判定覆盖。,条件覆盖(续),说明:虽然前面的一组测试用例同时达到了条件覆盖和判定覆盖,但是,并不是说满足条件覆盖就一定能满足判定覆盖。如果设计了下表中的这组测试用例,则虽然满足了条件覆盖,但只是覆盖了程序中第一个判定的取假分支c 和第二个判定的取真分支d,不满足判定覆盖的要求。,判定/条件覆盖,判定/条件覆盖实际上是将判定覆盖和条件覆盖结合起来的一种方法,即:设计足够的测试用例,使得判定中每个条件的所有可能取值至少满足一次,同时每个判定的可能结果也至少出现一次。根据判定/条件覆盖的基本思想,只需设计以下两个测试用例便可以覆盖4
22、个条件的8种取值以及4个判定分支。,判定/条件覆盖(续),分析:从表面上看,判定/条件覆盖测试了各个判定中的所有条件的取值,但实际上,编译器在检查含有多个条件的逻辑表达式时,某些情况下的某些条件将会被其它条件所掩盖。因此,判定/条件覆盖也不一定能够完全检查出逻辑表达式中的错误。例如:对于第一个判定(x3)&(z3和z3为假,则编译器将不再检查z5)来说,若条件x=4满足,就认为该判定为真,这时将不会再检查y5,那么同样也无法发现这个条件中的错误。,组合覆盖,组合覆盖的目的是要使设计的测试用例能覆盖每一个判定的所有可能的条件取值组合。对DoWork函数中的各个判定的条件取值组合加以标记:1、x3
23、,z3,z=10 记做T1-T2,第一个判定的取假分支 3、x=10 记做-T1-T2,第一个判定的取假分支 5、x=4,y5 记做T3 T4,第二个判定的取真分支 6、x=4,y5 记做-T3 T4,第二个判定的取真分支 8、x!=4,y=5 记做-T3-T4,第二个判定的取假分支,组合覆盖(续),根据组合覆盖的基本思想,设计测试用例如下:,分析:上面这组测试用例覆盖了所有8种条件取值的组合,覆盖了所有判定的真假分支,但是却丢失了一条路径abe。,路径覆盖,前面提到的5种逻辑覆盖都未涉及到路径的覆盖。事实上,只有当程序中的每一条路径都受到了检验,才能使程序受到全面检验。路径覆盖的目的就是要使
24、设计的测试用例能覆盖被测程序中所有可能的路径。根据路径覆盖的基本思想,在满足组合覆盖的测试用例中修改其中一个测试用例,则可以实现路径覆盖:,路径覆盖(续),分析:虽然前面一组测试用例满足了路径覆盖,但并没有覆盖程序中所有的条件组合(丢失了组合3和7),即满足路径覆盖的测试用例并不一定满足组合覆盖。说明:对于比较简单的小程序,实现路径覆盖是可能做到的。但如果程序中出现较多判断和较多循环,可能的路径数目将会急剧增长,要在测试中覆盖所有的路径是无法实现的。为了解决这个难题,只有把覆盖路径数量压缩到一定的限度内,如程序中的循环体只执行一次。在实际测试中,即使对于路径数很有限的程序已经做到路径覆盖,仍然
25、不能保证被测试程序的正确性,还需要采用其他测试方法进行补充。,基本路径测试方法,路径测试就是从一个程序的入口开始,执行所经历的各个语句的完整过程。从广义的角度讲,任何有关路径分析的测试都可以被称为路径测试。完成路径测试的理想情况是做到路径覆盖,但对于复杂性大的程序要做到所有路径覆盖(测试所有可执行路径)是不可能的。在不能做到所有路径覆盖的前提下,如果某一程序的每一个独立路径都被测试过,那么可以认为程序中的每个语句都已经检验过了,即达到了语句覆盖。这种测试方法就是通常所说的基本路径测试方法。,控制流图,控制流图(可简称流图)是对程序流程图进行简化后得到的,它可以更加突出的表示程序控制流的结构。控
26、制流图中包括两种图形符号:节点和控制流线。节点由带标号的圆圈表示,可代表一个或多个语句、一个处理框序列和一个条件判定框(假设不包含复合条件)。控制流线由带箭头的弧或线表示,可称为边。它代表程序中的控制流。,常见结构的控制流图,其中,包含条件的节点被称为判定节点(也叫谓词节点),由判定节点发出的边必须终止于某一个节点,由边和节点所限定的范围被称为区域。,控制流图,控制流图,对于复合条件(OR,AND,NAND,NOR),则可将其分解为多个单个条件,并映射成控制流图。例如:1 if a or b 2 x 3 else 4 y,环形复杂度,环形复杂度也称为圈复杂度,它是一种为程序逻辑复杂度提供定量尺
27、度的软件度量。环形复杂度的应用可以将环形复杂度用于基本路径方法,它可以提供:程序基本集的独立路径数量;确保所有语句至少执行一次的测试数量的上界。独立路径是指程序中至少引入了一个新的处理语句集合或一个新条件的程序通路。采用流图的术语,即独立路径必须至少包含一条在本次定义路径之前不曾用过的边。测试可以被设计为基本路径集的执行过程,但基本路径集通常并不唯一。,计算环形复杂度的方法,环形复杂度以图论为基础,为我们提供了非常有用的软件度量。可用如下三种方法之一来计算环形复杂度:控制流图中区域的数量对应于环形复杂度。给定控制流图G的环形复杂度V(G),定义为 V(G)=E-N+2 其中,E是控制流图中边的
28、数量,N是控制流图中的节点数量。给定控制流图G的环形复杂度V(G),也可定义为 V(G)=P+1 其中,P是控制流图G中判定节点的数量。,基本路径测试方法是在控制流图的基础上,通过分析控制结构的环形复杂度,导出执行路径的基本集,再从该基本集设计测试用例。基本路径测试方法包括以下4个步骤:(1)画出程序的控制流图。(2)计算程序的环形复杂度,导出程序基本路径集中的独立路径条数,这是确定程序中每个可执行语句至少执行一次所必须的测试用例数目的上界。(3)导出基本路径集,确定程序的独立路径。(4)根据(3)中的独立路径,设计测试用例的输入数据和预期输出。,基本路径测试方法(续),void Sort(i
29、nt iRecordNum,int iType)1 2 int x=0;3 int y=0;4 while(iRecordNum-0)5 6 if(iType=0)7 x=y+2;break;8 else9 if(iType=1)10 x=y+10;11 else12 x=y+20;13 14,4,基本路径测试方法(续),画出控制流图:计算环形复杂度:10(条边)-8(个节点)+2=4导出独立路径(用语句编号表示)路径1:414 路径2:46714 路径3:4691013414 路径4:4691213414,基本路径测试方法(续),设计测试用例:,4.3 循环测试方法,从本质上说,循环测试的目
30、的就是检查循环结构的有效性。通常,循环可以划分为简单循环、嵌套循环、串接循环和非结构循环4类。(1)测试简单循环。设其循环的最大次数为n,可采用以下测试集:跳过整个循环;只循环一次;只循环两次;循环 m 次,其中mn;分别循环 n-1、n 和 n+1 次。,循环测试方法(续),(2)测试嵌套循环。如果将简单循环的测试方法用于嵌套循环,可能的测试次数会随嵌套层数成几何级数增加。此时可采用以下办法减少测试次数:测试从最内层循环开始,所有外层循环次数设置为最小值;对最内层循环按照简单循环的测试方法进行;由内向外进行下一个循环的测试,本层循环的所有外层循环仍取最小值,而由本层循环嵌套的循环取某些“典型
31、”值;重复上一步的过程,直到测试完所有循环。(3)测试串接循环。若串接的各个循环相互独立,则可分别采用简单循环的测试方法;否则采用嵌套循环的测试方法。(4)对于非结构循环这种情况,无法进行测试,需要按结构化程序设计的思想将程序结构化后,再进行测试。,Z路径覆盖下的循环测试方法,Z路径覆盖是路径覆盖的一种变体,它是将程序中的循环结构简化为选择结构的一种路径覆盖。循环简化的目的是限制循环的次数,无论循环的形式和循环体实际执行的次数,简化后的循环测试只考虑执行循环体一次和零次(不执行)两种情况,即考虑执行时进入循环体一次和跳过循环体这两种情况。,在循环简化的思路下,循环与判定分支的效果是一样的,即:
32、循环要么执行、要么跳过。,产生测试用例,在实践中,除了前面给出的各种方法外,通常还可以采用以下三种方法来补充设计测试用例:(1)通过非路径分析得到测试用例 这种方法得到的测试用例是在应用系统本身的实践中提供的,基本上是测试人员凭工作经验的得到,甚至是猜测得到的。(2)寻找尚未测试过的路径并生成相应的测试用例 这种方法需要穷举被测程序的所有路径,并与前面已测试路径进行对比。(3)通过指定特定路径并生成相应的测试用例,最少测试用例数计算,为实现测试的逻辑覆盖,必须设计足够多的测试用例,并使用这些测试用例执行被测程序,实施测试。我们关心的是:对于某个具体的程序来说,至少需要设计多少个测试用例。这里提
33、供一种估算最少测试用例数的方法。我们知道,结构化程序是由 3 种基本控制结构组成:顺序型(构成串行操作)、选择型(构成分支操作)和重复型(构成循环操作)。为了把问题化简,避免出现测试用例极多的组合爆炸,把构成循环操作的重复型结构用选择结构代替。这样,任一循环便改造成进入循环体或不进入循环体的分支操作了。,最少测试用例数计算(续),用N-S图表示程序的3种基本控制结构:,图中A、B、C、D、S均表示要执行的操作,P是可取真假值的谓词,Y表真值,N表假值。图中的(c)和(d)两种重复型结构代表了两种循环。在做了简化循环的假设以后,对于一般的程序控制流,我们只考虑选择型结构。事实上它已经能体现顺序型
34、和重复型结构了。,最少测试用例数计算(续),显然,要测试这个小程序,需要至少提供4个测试用例才能作到逻辑覆盖,使得ac、ad、bc及bd操作均得到检验。其实,这里的4是图中的第1个分支谓词引出的两个操作,及第2个分支谓词引出的两个操作组合起来而得到的,即 22=4。并且,这里的2是由于两个并列的操作,即1+1=2 而得到的。,例如,下图表达了两个顺序执行的分支结构。当两个分支谓词P1和P2取不同值时,将分别执行a或b及c或d操作。,最少测试用例数计算(续),对于一般的、更为复杂的问题,估算最少测试用例个数的原则也是同样的:如果在N-S图中存在有并列的层次A1、A2,A1和A2的最少测试用例个数
35、分别为a1、a2,则由 A1、A2 两层所组合的 N-S图对应的最少测试用例数为a1a2。如果在N-S图中不存在有并列的层次,则对应的最少测试用例数由并列的操作数决定,即N-S图中除谓词之外的操作框的个数。,最少测试用例数计算(续),例:如下图所示的两个N-S图,至少需要多少个测试用例完成逻辑覆盖?,对于第一个N-S图:由于图中并不存在并列的层次,最少测试用例数由并列的操作数决定,即为1+1+1=3。对于第二个N-S图:由于图中没有包含并列的层次,最少测试用例数仍由并列的操作数决定,即为1+1+1+1+1=5。,最少测试用例数计算(续),例:如下图所示的N-S图,至少需要多少个测试用例完成逻辑
36、覆盖?,分析该N-S图:图中的2345和67是并列的两层。其中,2345层对应的最少测试用例数为1+1+1+1+1=5,67层对应的测试用例数为1+1+1=3,2345和67这两层组合后对应的测试用例数为53=15。最后,由于两层组合后的部分是不满足谓词1时所要做的操作,还要加上满足谓词1要做的操作,因此整个程序所需测试用例数为15+1=16。,黑盒测试法的概念,黑盒测试被称为功能测试或数据驱动测试。在测试时,把被测程序视为一个不能打开的黑盒子,在完全不考虑程序内部结构和内部特性的情况下进行。采用黑盒测试的目的主要是在已知软件产品所应具有的功能的基础上,进行:(1)检查程序功能能否按需求规格说
37、明书的规定正常使用,测试各个功能是否有遗漏,检测性能等特性要求是否满足。(2)检测人机交互是否错误,检测数据结构或外部数据库访问是否错误,程序是否能适当地接收输入数据而产生正确的输出结果,并保持外部信息(如数据库或文件)的完整性。(3)检测程序初始化和终止方面的错误。,2 黑盒测试法的概念(续),软件,功能与性能是否满足要求输出是否正确外部信息能否保持完整是否存在初始化或终止性错误,三角形问题与NextDate函数,1、三角形问题 输入三个整数a、b、c,分别作为三角形的三条边,现通过程序判断由三条边构成的三角形的类型为等边三角形、等腰三角形、一般三角形(特殊的还有直角三角形),以及构不成三角
38、形。现在要求输入三个整数a、b、c,必须满足以下条件:条件1 1a100 条件4 ab+c 条件2 1b100 条件5 ba+c 条件3 1c100 条件6 ca+b,如果输入值a、b、c不满足条件1、条件2和条件3,程序给出“边的取值超出允许范围”的信息。如果输入值a、b、c 满足条件1、条件2和条件3,则输出下列四种情况之一:(1)如果不满足条件4、条件5和条件6中的一个,则程序输出为“非三角形”。(2)如果三条边相等,则程序输出为“等边三角形”。(3)如果恰好有两条边相等,则程序输出为“等腰三角形”。(4)如果三条边都不相等,则程序输出为“一般三角形”。结论:三角形问题的复杂之处在于输入
39、与输出之间的关系比较复杂。,2、NextDate函数 NextDate函数说明另一种复杂的关系,即输入变量之间逻辑关系的复杂性。NextDate函数包含三个变量month、day和year,函数的输出为输入日期后一天的日期。要求输入变量month、day和year均为整数值,并且满足下列条件:条件1 1 month 12 条件2 1 day 31 条件3 1912 year 2050结论:在NextDate函数中有两种复杂性的输入来源,一是输入域的复杂性,二是确定闰年的规则并要增加“额外天”。,等价类划分法,1 等价类的划分原则2 等价类划分法的测试用例设计3 常见等价类划分测试形式4 使用等
40、价类划分法测试的实例,等价类划分法,等价类划分法是一种重要的、常用的黑盒测试方法,它将不能穷举的测试过程进行合理分类,从而保证设计出来的测试用例具有完整性和代表性。举例:设计这样的测试用例,来实现一个对所有实数进行开平方运算(y=sqrt(x))的程序的测试。思考方向:由于开平方运算只对非负实数有效,这时需要将所有的实数(输入域x)进行划分,可以分成:正实数、0 和 负实数。假设我们选定+1.4444代表正实数,-2.345代表负实数,则为该程序设计的测试用例的输入为+1.4444、0 和-2.345。,等价类划分法(续),等价类划分法是把所有可能的输入数据,即程序的输入域划分为若干部分(子集
41、),然后从每一个子集中选取少数具有代表性的数据作为测试用例。所谓等价类是指某个输入域的子集合。在该子集合中,各个输入数据对于揭露程序中的错误都是等效的,它们具有等价特性,即每一类的代表性数据在测试中的作用都等价于这一类中的其它数据。这样,对于表征该类的数据输入将能代表整个子集合的输入。因此,可以合理的假定:测试某等价类的代表值就是等效于对于这一类其它值的测试。,等价类的划分原则,等价类是输入域的某个子集合,而所有等价类的并集就是整个输入域。因此,等价类对于测试有两个重要的意义:完备性整个输入域提供一种形式的完备性无冗余性若互不相交则可保证一种形式的无冗余性如何划分?先从程序的规格说明书中找出各
42、个输入条件,再为每个输入条件划分两个或多个等价类,形成若干的互不相交的子集。采用等价类划分法设计测试用例通常分两步进行:(1)确定等价类,列出等价类表。(2)确定测试用例。,等价类的划分原则(续),划分等价类可分为两种情况:(1)有效等价类 是指对软件规格说明而言,是有意义的、合理的输入数据所组成的集合。利用有效等价类,能够检验程序是否实现了规格说明中预先规定的功能和性能。(2)无效等价类 是指对软件规格说明而言,是无意义的、不合理的输入数据所构成的集合。利用无效等价类,可以鉴别程序异常处理的情况,检查被测对象的功能和性能的实现是否有不符合规格说明要求的地方。,等价类的划分原则(续),进行等价
43、类划分的依据:,(1)按照区间划分 在输入条件规定了取值范围或值的个数的情况下,可以确定一个有效等价类和两个无效等价类。,例:输入值是学生成绩,范围是0100,等价类的划分原则(续),进行等价类划分的依据:,(2)按照数值划分 在规定了一组输入数据(假设包括 n个 输入值),并且程序要对每一个输入值分别进行处理的情况下,可确定 n 个有效等价类(每个值确定一个有效等价类)和一个无效等价类(所有不允许的输入值的集合),例:输入值是学历,允许值:专科、本科、硕士、博士,有效等价类,专科,本科,硕士,博士,无效等价类:其它任何学历,等价类的划分原则(续),(3)按照数值集合划分 在输入条件规定了输入
44、值的集合或规定了“必须如何”的条件下,可以确定一个有效等价类和一个无效等价类(该集合有效值之外)。,例:程序输入条件为取值为奇数的整数x,则有效等价类为x的值为奇数的整数,无效等价类为x的值不为奇数的整数。,1,3,5,7,,0,2,4,6,,有效等价类,无效等价类,等价类的划分原则(续),(4)按照限制条件或规则划分 在规定了输入数据必须遵守的规则或限制条件的情况下,可确定一个有效等价类(符合规则)和若干个无效等价类(从不同角度违反规则)。,例:程序输入条件为以字符a开头、长度为8的字符串,并且字符串不包含a z之外的其它字符,则有效等价类为满足了上述所有条件的字符串,无效等价类为不以a开头
45、的字符串、长度不为8的字符串和包含了a z之外其它字符的字符串。,(5)细分等价类 在确知已划分的等价类中各元素在程序中的处理方式不同的情况下,则应再将该等价类进一步划分为更小的等价类,并建立等价类表。,等价类划分法的测试用例设计,在设计测试用例时,应同时考虑有效等价类和无效等价类测试用例的设计。根据已列出的等价类表可确定测试用例,具体过程如下:(1)首先为等价类表中的每一个等价类分别规定一个唯一的编号。(2)设计一个新的测试用例,使它能够尽量覆盖尚未覆盖的有效等价类。重复这个步骤,直到所有的有效等价类均被测试用例所覆盖。(3)设计一个新的测试用例,使它仅覆盖一个尚未覆盖的无效等价类。重复这一
46、步骤,直到所有的无效等价类均被测试用例所覆盖。,常见等价类划分测试形式,针对是否对无效数据进行测试,可以将等价类测试分为 标准等价类测试和健壮等价类测试。标准等价类测试不考虑无效数据值,测试用例使用每个等价类中的一个值。健壮等价类测试主要的出发点是考虑了无效等价类。对有效输入,测试用例从每个有效等价类中取一个值;对无效输入,一个测试用例有一个无效值,其他值均取有效值。健壮等价类测试存在两个问题:(1)需要花费精力定义无效测试用例的期望输出(2)对强类型的语言没有必要考虑无效的输入,常见等价类划分测试形式(续),例:现有程序,有两个输入x1和x2a=x1=d,区间a,bb,cc,de=x2=g,
47、区间e,ff,g,a,b,c,d,e,f,g,x1,x2,a,b,c,d,e,f,g,x1,x2,标准等价测试,健壮等价测试,使用等价类划分法测试的实例(1),实例1:某报表处理系统要求用户输入处理报表的日期,日期限制在2001年1月至2005年12月,即系统只能对该段期间内的报表进行处理,如日期不在此范围内,则显示输入错误信息。系统日期规定由年、月的6位数字字符组成,前四位代表年,后两位代表月。如何用等价类划分法设计测试用例,来测试程序的日期检查功能?,使用等价类划分法测试的实例(1),步骤1:等价类划分,输入等价类 有效等价类 无效等价类,6位数字字符(1),有非数字字符(4)少于6个数字
48、字符(5)多于6个数字字符(6),年份范围,在20012005之间(2),小于2001(7)大于2005(8),月份范围,在112之间(3),“报表日期”输入条件的等价类表,小于1(9)大于12(10),报表日期的类型及长度,使用等价类划分法测试的实例(1),步骤2:设计有效类的测试用例,对表中编号为1,2,3的3个有效等价类用一个测试用例覆盖,使用等价类划分法测试的实例(1),步骤3:设计无效类的测试用例,对上表中每个无效类至少设计一个测试用例,使用等价类划分法测试的实例(2),实例2 三角形问题分析:(1)三角形问题的等价类测试用例 输入条件为:整数、三个数、取值在1100之间 可参照上面
49、的例子画出输入条件的等价类表(略),从而得到测试用例。,使用等价类划分法测试的实例(2),分析:(2)标准和健壮等价类划分方法的测试用例。在多数情况下,是从输入域划分等价类的,但并非不能从被测程序的输出域反过来定义等价类,事实上,这对于三角形问题却是最简单的划分方法。在三角形问题中,有四种可能的输出:等边三角形、等腰三角形、一般三角形和非三角形。利用这些信息能够确定下列输出(值域)等价类。R1=:边为a,b,c的等边三角形 R2=:边为a,b,c的等腰三角形 R3=:边为a,b,c的一般三角形 R4=:边为a,b,c不能组成三角形,三角形问题,三角形问题的4个标准等价类测试用例,三角形问题的7
50、个健壮等价类测试用例,使用等价类划分法测试的实例(3),实例3 保险公司计算保费费率的程序 某保险公司的人寿保险的保费计算方式为:投保额保险费率 其中,保险费率依点数不同而有别,10点及10点以上保险费率为0.6%,10点以下保险费率为0.1%;而点数又是由投保人的年龄、性别、婚姻状况和抚养人数来决定,具体规则如下:,计算保费费率的程序,(1)分析程序规格说明中给出和隐含的对输入条件的要求,列出等价类表(包括有效等价类和无效等价类)。年龄:一位或两位非零整数,值的有效范围为199性别:一位英文字符,只能取值M或F婚姻:字符,只能取值已婚或未婚抚养人数:空白或一位非零整数(19)点数:一位或两位