资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,第5章 结构化实现,编码也是一种创造性的活动:,数据结构的选择,变量的选择,内部文档,灵活性,编码涉及的问题,使用何种计算机语言编码?,采用何种编码风格?,怎样使编码能正确表现技术设计?,如何提高编码效率?,怎样使程序具有可读性?,如何正确使用可重用模块?,如何使模块成为以后可重用的模块?,5.1.1 选择程序设计语言,程序设计语言是人与计算机通信的基本工具,一个系统只少需要使用一种计算机语言实现,一个系统也可能需要使用几种不同的计算机语言实现,1.计算机语言的分类,机器语言:,面向机器,机器码表示,汇编语言:,面向机器,符号代码表示,面向过程语言:,C,FORTRAN,PASCAL,COBOL,BASIC,Ada,面向问题语言,:,4GL,Unix Shell等,面向对象语言,:,C+,VB,VC,Delphi,Jave等,专用语言:,人工智能语言(LISP,PROLOG),数组和向量运算语言APL,,数据库语言:,SQL,各种数据库自身的程序设计语言,2.选择程序设计语言的根据,用户的要求,项目的特点,工程规模,软件应用领域,软件组织标准,程序设计语言特性,编码人员的知识,软件可移植性,软件重用,测试与维护,算法及计算的复杂程度,数据数据结构的复杂程序,运行效率,该程序设计语言的发展前景,5.1.2 编码风格,编码是一种创造性的活动,软件的质量主要取决于设计的质量,编码对于软件的质量也是很重要的,编码要有全局观念(要考虑到测试、集成、维护等),编码发生在两个阶段:,编码阶段:,根据软件设计产生源程序,是软件产品的一部分,质量要求高,测试阶段:,编写测试程序,只需满足测试要求,质量要求不高,软件开发的效率应着眼于整体效率,编码,风格,编码程序员在编码时习惯使用的方式,编码目标:强调“代码效率”,强调“清晰易读”,编码风格:追求“聪明”和“技巧”,提倡“简明”和“直接”,良好的编码风格能在一定程度上弥补程序设计语言的缺点,不好的编码风格,即使使用再好的程序设计语言,也很难写出高质量的程序,在团队环境开发时,更应强调协调、一致、标准的风格,以利于互相沟通,减少因不协调而引起的问题,编码应遵循的一些准则,1.程序内部文档,(1)组件的“头注释块”Header Comment Block,包括:,组件编号,组件名称,组件的功能,编写者姓名 E-Mail 编写时间,最近修改者姓名 E-Mail 最近修改时间,组件版本号,组件的性能要求,主要算法描述,接口方式、输入参数、输出结果,重要数据结构的名称、类型、用途,调用该组件的组件,该组件调用的组件,测试员姓名,测试程序名,测试数据文件或者数据库名,其他说明,软件组织的软件标准中对组件的头注释块的内容、顺序和表示方式一般都有具体的规定,*,*Component No.:1103 *,*Component Name:Root*,*,*,Program content,(2)程序内部注释,在程序内部设置一些注释语句,对某些重要程序成份、算法、结构进行适当说明。,例:,*move the Point to next position,Point=point+1,(3)选择含义明确的名字,若使用缩写名字,应用注释加以说明。,例:,week_wage=(hours_rate*hours)+0.5*(hours_rate)*(hour s-40.),比下面的写法意义明确:,z=(a*b)+(0.5)*(a)*(b-40.),(4)良好的组织结构,有助于对程序的理解,例:,if(xcoordslope2),result=0;,else result=-1;,elseif(slope1slope2),result=2;,elseif(slope1slope2),result=3;,result=4;,if(xcoordslope2),result=0;,else,result=-1;,elseif(slope1slope2),result=2;,elseif(slope1slope2),result=3;,result=4;,2.外部文档,内部文档是为程序员写的,外部文档是为那些甚至是没有读过代码的人写的,外部文档能比内部文档更合理且详细地对组件用解释说明。,若把头注释看作是程序的概要,则外部文档则是对程序的详细介绍。,外部文档回答了谁使用该系统,使用什么内容,为什么使用该系统,在何时何地使用以及如何使用该系统。,外部文档包括:,系统中组件的概述,组件组(例如,用户界面组件,数据库管理组件,快速计算组件等),图及描述每个组件的说明:描述数据如何被一个或多个组件使用和共享,通常综述描述信息是怎么从一个组件传递到另一个组件的。,对象类及其继承层次:属于类型定义和数据范畴。,外部组件文档是系统文档概述一部分。在组件被编写的时候,相关的组件的结构和数据流已经在设计文当中进行了详细的描述。从某种意义来说,设计是外部文档的框架,细节由描述讨论组件的特性提供。,3.数据说明,组件内部数据说明的顺序应标准化,例如:说明语句按类型排列,按字母顺序排列等,一个说明语句说明多个量时,顺序应标准化,例如:各个被说明的量按字母顺序排列,尽量不使用全局变量或标识,全局变量可能加大组件间的耦合度。,4.数据结构,使用复杂的数据结构时,用注释语句实现该数据结构的方法和特点,使用数据结构结构简化程序结构,4.程序结构,尽量不要为了节省空间,而将多个语句写在一行上,尽量避免复杂的条件判断,尽量减少对“非”条件的判断,以免引起概念上的误解,避免使用太多层次循环和嵌套,利用括号使复杂的逻辑表达式或算术表达式的运算次序清晰直观,采用结构化控制结构,设计伪码简化程序结构,5.输入/输出,输入输出局部化,对所有输入的数据都进行检验,检查输入项重要组合的合法性,保持输入格式简单,当数据量较大时,使用数据结束标记,不要要求用户指定数据的个数,输入时有明确的提示信息,详细说明可用的选择或办界值,当程序设计语言对数据格式有严格要求时,应保持输入格式的一致性,设计良好的输出报表,为所有输出数据加说明标志,6.提高效率,效率是指处理机响应时间和存储器容量的利用率。,效率是性能要求,效率是靠好的设计提高的,程序的效率与程序的简单程序是一致的,效率主要取决于详细设计确定的算法,好的编码风格也会提高效率,提高程序的效率应考虑以下因素:,(1)程序运行时间,编码前先对算法化简,编码前先化简算术表达式和逻辑表达式,在循环嵌套中,将与内层循环无关的语句移到外层循环中,尽量避免使用多维数组,若使用转移语句可以使程序结构简单,也可以使用此类语句,不要混合使用不同的数据类型,尽量使用整数运算和布尔表达式,(2)存储效率,(3)输入输出效率,设置输入输出缓冲区,减少通信的额外开销,对外存储器选用最简单的访问方法,外存储器的输入输出以信息组为单位,7.重用,生产者重用Producer reuse:设计的组件将在以后的应用中被重用,消费者重用consumer reuse:使用以前为其他工程开发的组件,有些公司对一些组件评价并修改后,构建了部门或公司标准重用组件库。,重用的原则:,消费者重用:可用四个关键特征来检验将被重用的组件:,该组件是否能执行所需的功能,提供所需的数据?,若需做少量修改,修改的费用是否少于重新编写的费用?,是否有完整的文档?是否不必逐行阅读代码就能理解?,是否有测试的完整记录和 版本?能否确信其没有缺陷?,必须估计为使系统能与可重用部件相结合所需编写的代码量。,生产者重用:,编写将来重用的组件应注意的问题,使组件具有通用性。,将可能改变的部分与可能不变的部分相分离。,使组件的接口具有通用性,定义良好,包括任何发现和改正缺陷的信息。,使用确切的命名规则。,将数据结构和算法文档化。,使通信部分与错误处理部分隔离,并且容易修改。,软件测试主要内容,测试的概念,软件故障与失败(故障的分类),测试的过程(单元测试,集成测试,系统测试),单元测试,集成测试,测试计划,自动测试工具,何时停止测试,开发大规模软件时,不可避免地产生各种错误:,开发周期长,问题错综复杂,开发人员众多,配合和沟通不利,人的主观认识不可能完全符合客观现实,早期遗留的故障,在后期各阶段逐级放大,造成更大的故障,无论何时产生的任何一个故障fault,都是一种隐患,软件交付使用,投入运行后,都可能会表现出来:,轻则使软件不能正常工作,需要修改,重则软件得不到正确的运行结果,严重情况下,可能造成直接或间接的重大损失,因此,在软件投入使用前,必须进行严格的测试。,软件测试的目的:,发现软件中的故障,诊断故障产生的原因,以便纠正故障。,软件测试的阶段:,单元测试 Unit testing(Module testing,Component ting),集成测试Integration testing,系统测试System testing,本章介绍测试的概念、单元测试和集成测试,Fault:,软件开发过程中可能存在的问题,Failure:,软件不能按照需求描述的方式工作,Fault在一定条件下,可能会变成Failure。但并不是所有Fault都一定会变成Failure.,Failure可能由于多种原因所致:,需求规格错误,或遗漏了需求问题,给定的软件和硬件无法实现需求规格中的问题,系统设计可能有故障,程序设计可能有故障,程序编码可能故障,无论多么出色的程序员,都可能会产生故障,因此,必须用各种方法检查程序,排除故障,故障识别与故障改正:,故障识别Fault identification:确定引起失败是什么故障的过程,故障改正Fault correction:修改系统,去除故障的过程,Bug:程序中存在的任何一种破坏正常运行的问题或缺陷,例如:测试求解方程ax2+by+c=0的程序,系统测试System testing,投入测试的人员数量受限制,逻辑运算的优先级错误,输入(A,B,X),输出(A,B,X),此类故障难以识别和改正,if(xcoordycoord),逻辑表达式表示不正确,elseif(slope11 and b=0,a=2 or x1,x=x/a,x=x+1,s,2,1,b,a,d,3,4,e,c,T,T,F,F,6,7,5,为了使每个语句都至少执行一次,执行的顺序应为:sacbed,只需输入测试数据:,a=2,b=0,x=4,语句覆盖对组件的逻辑覆盖最少,是一种弱覆盖。,某些逻辑错误无法查到,例如:,x1 or b=0 a=2 and x1,1、语句覆盖,使得程序中每个语句至少都能被执行一次。,A1,AND,B=0,X:=X/A,A=2,OR,X1,X:=X+1,a,b,c,d,e,满足语句覆盖的情况:,执行路径:ace,选择用例:,(2,0,4),(2,0,3),用例格式:,输入(A,B,X),输出(A,B,X),Y,N,Y,N,(2)分支测试branch testing,不仅每条语句至少执行一次,每个判定的每种可能的结果都应至少执行一次。,覆盖1:sacbd,测试用例:,a=3,b=0,x=3,覆盖2:sabed,测试用例:,a=2,b=1,x=1,判定覆盖比语句覆盖能力强,但对组件的逻辑覆盖程序仍不高,本用例未覆盖路径:,Sacbed和sabd,Start,End,a1 and b=0,a=2 or x1,x=x/a,x=x+1,s,2,1,b,a,d,3,4,e,c,T,T,F,F,6,7,5,2、判定覆盖,使得程序中每个判定至少为TRUE 或FALSE各一次。,A1,AND,B=0,X:=X/A,A=2,OR,X1,X:=X+1,a,b,c,d,e,覆盖情况:,应执行路径,ace,abd,或:acd abe,选择用例(其一):,(2,0,4),(2,0,3)ace,(1,1,1),(1,1,1)abd,(2,1,1),(2,1,2)abe,(3,0,3),(3,1,1)acd,Y,Y,N,N,(3)条件测试Condition Testing,不仅每条语句至少执行一次,每个判定表达式中的条件都取到各种可能的结果。,本例中有两个条件表达式,每个,条件表达式有两个条件。,为了做到条件覆盖,测试数据应,使a点有:,a1,a,1,b=0,b0,在b点有:,a=2,a,2,x1,x1,只需使用以下两组数据就可实现上述覆盖,a=2,b=0,x=4,覆盖sacbed,a=1,b=1,x=1,覆盖sabd,条件覆盖比判定覆盖强,本测试用例也可以满足判定覆盖要求,Start,End,a1 and b=0,a=2 or x1,x=x/a,x=x+1,s,2,1,b,a,d,3,4,e,c,T,T,F,F,6,7,5,3、条件覆盖,A1,AND,B=0,X:=X/A,A=2,OR,X1,X:=X+1,a,b,c,d,e,使得判定中的每个条件获得各种可能的结果。,应满足以下覆盖情况:,判定一:A1,A,1,B=0,B,0,判定二:A=2,A,2,X1,X1,选择用例:,(2,0,4),(2,0,3),(1,1,1),(1,1,1),N,N,Y,Y,2,A,1,A,2,0,B=0,4,X1,1,A1,A=2,1,B,0,1,X1,注意,:(1,0,3),(1,0,4),(2,1,1),(2,1,2),满足条件覆盖,但不满足判断覆盖。,(4)分支/条件测试Branch and Condition Testing,条件测试不一定能覆盖判定覆盖。,例如:,a=2,b=0,x=1,a=1,b=1,x=2,满足条件覆盖,但不能满足判,定覆盖。,判定/条件覆盖为选择足够的测试,用例,同时满足两种覆盖。,例如:,a=2,b=0,x=4,A=1,b=1,x=1,Start,End,a1 and b=0,a=2 or x1,x=x/a,x=x+1,s,2,1,b,a,d,3,4,e,c,T,T,F,F,6,7,5,4、判定/条件覆盖,同时满足判断覆盖和条件覆盖。,A1,AND,B=0,X:=X/A,A=2,OR,X1,X:=X+1,a,b,c,d,e,应满足以下覆盖情况:,条件:A1,A,1,B=0,B,0,A=2,A,2,X1,X1,应执行路径,ace,abd,或:acd abe,选择用例:,(2,0,4),(2,0,3)(ace),(1,1,1),(1,1,1)(abd),Y,Y,N,N,(5)条件组合测试 Combining Condition Testing,使每个条件表达式中条件的各种可能组合都至少出现一次。,本例中,共有八种组合:,(a),a1,b=0,(b),a1,b0,(c),a,1,b=0,(d),a,1,b0,(e),a=2,x1,(f),a=2,x1,(g),a2,x1,(h),a2,x1,测试用例:,a=2,b=0,x=4:,(a)(e),(sacbed),a=2,b=1,x=1:,(b)(f),(sabed),a=1,b=0,x=2:,(c)(g),(sabed),a=1,b=1,x=1:,(d),(h),(sabd),这组测试用例可以满足上述各种覆盖,其覆盖能力最强,Start,End,a1 and b=0,a=2 or x1,x=x/a,x=x+1,s,2,1,b,a,d,3,4,e,c,T,T,F,F,6,7,5,5、条件组合覆盖,使得每个判定中条件的各种可能组合都至少出现一次。,A1,X:=X/A,A=2,X:=X+1,a,b,c,d,e,B=0,X1,Y,N,Y,N,Y,N,Y,N,编译系统下的执行情况:,部分路径未被执行。,满足以下覆盖情况:,A1,B=0 ,A1,B,0,A,1,B=0 ,A,1,B0,A=2,X1,A=2,X1,A,2,X1,A,2,X1,选择用例:,(2,0,4),(2,0,3),(2,1,1),(2,1,2),(1,0,3),(1,0,4),(1,1,1),(1,1,1),5.4 控制结构测试,5.4.1,基本,路径测试,5.4.2,条件测试,基本路径测试,基本路径测试方法把覆盖的路径数压缩到一定限度内,,程序中的循环体最多只执行一次,。,它是在程序控制流图的基础上,,分析控制构造的环路复杂性,,,导出基本可执行路径集合,,,设计测试用例的,方法。设计出的测试用例要保证在测试中,程序的每一个可执行语句至少要执行一次。,1.程序的控制流图,符号为控制流图的一个结点,表示一个或多个无分支的PDL语句或源程序语句。箭头为边,表示控制流的方向。,在选择或多分支结构中,分支的汇聚处应有一个汇聚结点。,边和结点圈定的区域叫做区域,,当对区域计数时,图形外的区域也应记为一个区域。,如果判断中的条件表达式是由一个或多个逻辑运算符,(OR,AND,.),连接的复合条件表达式,则需改为 一系列,只有单个条件的嵌套的判断,。,2.程序环路复杂性,程序的环路复杂性给出了,程序基本路径集中的独立路径条数,,这是确保程序中每个可执行语句至少执行一次所必需的测试用例数目的上界。,从控制流图来看,一条独立路径是至少包含有一条在其它独立路径中从未有过的边的路径。,例如,在图示的控制流图中,一组独立的路径是,path1,:1-11,path2,:1-2-3-4-5-10-1-11,path3,:1-2-3-6-8-9-10-1-11,path4,:1-2-3-6-7-9-10-1-11,路径 path1,path2,path3,path4组成了控制流图的一个基本路径集。,3.导出测试用例,导出测试用例,,确保基本路径集中的每一条路径的执行。,根据判断结点给出的条件,选择适当的数据以保证某一条路径可以被测试到 用逻辑覆盖方法。,每个,测试用例执行之后,与预期结果进行比较,。如果所有测试用例都执行完毕,则可以确信程序中所有的可执行语句至少被执行了一次。,必须注意,一些独立的路径(如例中的路径1),往往不是完全孤立的,有时它是程序正常的控制流的一部分,这时,这些路径的测试可以是另一条路径测试的一部分。,条件测试路径选择,当程序中判定多于一个时,形成的分支结构可以分为两类:,嵌套型分支结构,和,连锁型分支结构,。,对于嵌套型分支结构,若有,n,个判定语句,需要,n,+1,个测试用例;,对于连锁型分支结构,若有,n,个判定语句,需要有,2,n,个测试用例,覆盖它的,2,n,条路径。,5.4.4 循环测试 Loop Testing,用于测试循环结构的有效性,在结构化程序中,循环通常有三类:,简单循环,嵌套循环,串接循环,(1)简单循环,跳过循环,只跳过循环一次,通过循环两次,通过循环m次,其中mn-1(n为循环次数),通过循环n-1,n,n+1次,例:求最小值,k,=,i,;,for(,j,=,i,+1;,j,=,n,;,j,+),if(A,j,A,k,),k,=,j,;,k,=,i,;,j,=,i,+1;,j,=,n,?,A,j,A,k,?,k,=,j,j,+,f,d,c,a,b,e,测试用例选择,(2)嵌套循环,可以将简单循环的测试方法应用到嵌套循环中,但测试数可能随着嵌套层数的增加成几何级数增长。,提一种能减少测试数的方法:,从最内层循环开始测试,把所有,外层循都设为最小值。,对最内层循环使用简单循环测试,方法,使外层循环的迭代参数取,最小值,并为越界值或非法值增,加一些额外测试。,由内向外,对下一个循环进行测试,,但保持所有外层循环为最小值,其他嵌套循环为“典型”值。,继续进行下去,直到测试完全部循环为止。,(3)串接循环,串接循环的各个循环彼此独立,可采用简单循环测试方法。,若前一个循环的计数器值是后一个循环的初始值,可采用嵌套循环测试方法。,5.5,黑盒测试技术,等价划分,边界值分析,错误推测法,5.5.1 等价划分,等价类,Equivalence Classes,将所有可能的输入输出数据域划分成若干个数据的等价类,每类取一组具有代表性的典型数据作为测试用例,这组测试用例最可能发现组件中的故障。,一个理想的测试用例应能发现一类故障。,划分等价类应根据需求规格文档。,等价类划分原则:,输入等价类,有效等价类,无效等价类,输出等价类,有效等价类,无效等价类,等价类划分的启发规则:,如果规定了一个数输入值的范围,可划分为:,一个有效等价类:,在输入值范围内的一个数,两个无效等价类:,一个小于最小值的数,一个大于最大值,如果规定了输入数据的个数,可划分:,一个有效等价类:,输入数据个数等于规定的个数,两个无效等价类:,输入数据个数,少于规定的个数,输入数据个数,少于规定的个数,如果规定了输入数据的一组值,组件对不同输入做不同处理,一个有效等价类:,每个数取一个允许的输入值,两个无效等价类:,每个数取一个大于允许输入值的数,每个数取一个大于允许输入值的数,如果规定了输入数据必须遵循的规则,可划分:,一个有效等价类:,符合规则的数,若干个无效等价类:,各种不同的违反规则的数,如果规定了输入数据为整型,可划分为:,三个有效等价类:,正整数,零,负整数,等等,说明:,上述规则大部分也同样适用于输出数据。,划分无效等价类时要注意编译程序的错误检查功能。,例:,计算一个任意三角形的面积。,S=,P=,设计测试该程序的等价类测试用例。,设计测试用例的根据:,(1)输入的数据必须是三个,(2)每个数必须在其允许的取值范围内,(3)任何两条边长之和应大于第三条边,(4)输入的数为整型数,a,c,b,等价类划分,测试项目,等价类,测试内容,测试用例,期望输出,输入数据个数,有效等价类,输入3条边,a=3,b=4,c=5,6,无效等价类,只输入1条边a,只输入1条边b 只输入1条边c,a=3,b=4,c=5,未输入b,c,未输入a,c,未输入a,b,只输入2条边 a,b 只输入2条边b,c 只输入2条边a,c,a=3,b=4,b=4,c=5,a=3,c=5,未输入c,未输入a,未输入b,输入4条边以上a,b,c,d,a=3,b=4,c=5,d=6,输入数据太多,数据的取值范围,a的有效等价类,2a 8,a=5,输出正常,a的无效等价类,a8,a=1,a=9,“a8”,b的有效等价类,3b 6,b=4,输出正常,b的无效等价类,a6,b=2,b=7,“b6”,3c 7,等价类划分(续),测试项目,等价类,测试内容,测试用例,期望输出,构成三角的条件,有效等价类1,a+bc,a=5,b=3,c=6,输出正常,无效等价类1,a+b=c,a+bc,a=2,b=3,c=5,a=2,b=3,c=7,“a+bb,a=5,b=3,c=6,输出正常,无效等价类2,a+c=b,a+cb,a=3,b=6,c=3,a=2,b=6,c=3,“a+c=b”,有效等价类3,b+ca,a=5,b=3,c=4,输出正常,无效等价类3,b+c=a,b+ca,a=7,b=3,c=4,a=7,b=3,c=3,“b+c=a”,5.5.2 边界值分析,组件在处理边界值时最容易发生故障。,例如:数值的上下限,下标的上下限,数组元素的上下限等,选择测试用例时,重点测试边界附近的情况:,正好等于边界值,刚好小于边界值,刚好大于边界值,5.5.3 错误推测,人们也可以靠经验和直觉推测程序中可能存在的各种错误,从而有针对性地编写检查这些错误的例子。这就是错误推测法。,错误推测法的基本想法是:,列举出程序中所有可能有的错误和容易发生错误的特殊情况,根据它们选择测试用例,。,实用测试策略,用黑盒法设计基本测试用例,用白盒法补充必要的测试用例,在任何情况下,都应使用边界值分析方法,必要时用等价划分法补充测试用例,必要时再用故障推测法补充测试用例,对照组件的逻辑,检查已设计出的测试用例,白盒测试,逻辑测试(语句测试 分支测试 条件测试等),循环测试,基本路径测试,条件测试,数据流测试,黑盒测试,等价类划分,边界值分析,错误推测,5.6 测试策略,5.6.1 测试步骤,单元测试(Unit testing,Component testing,unit testing),集成测试(Integration testing),功能测试(Function testing),性能测试(Performance testing),确认测试(Validation testing),验收测试(Acceptance testing),安装测试(Installation testing),系统测试(System testing),软件测试的策略,测试过程按4个步骤进行,即,单元测试,、,组装测试,、,确认测试,和,系统测试,。,开始是,单元测试,,集中对用源代码实现的每一个程序单元进行测试,检查各个程序模块是否正确地实现了规定的功能。,组装测试,把已测试过的模块组装起来,主要对与设计相关的软件体系结构的构造进行测试。,确认测试,则是要检查已实现的软件是否满足了需求规格说明中确定了的各种需求,以及软件配置是否完全、正确。,系统测试,把已经经过确认的软件纳入实际运行环境中,与其它系统成份组合在一起进行测试。,5.6.2 单元测试,单元测试的目的:查找组件内部的故障,单元测试的方法:白盒测试法、黑盒测试法,单元测试的任务:,(1)组件接口测试,组件是否能正确接收数据,是否能正确地输出数据。,组件中参数个数与组件接口参数个数是否相等,参数及变量的属性是否匹配,参数及变量的单位是否匹配,组件中是否修改了只用于输入的变量,(2)局部数据结构,数据类型说明错误或不相容,使用了未赋值或未初始化的变量,初始化错误或缺省值不正确,变量名错误(拼写错误,被截短),数据类型不相容,数据溢出,(3)重要的执行通路,比较数据类型不同的变量,逻辑表达式表示不正确,逻辑运算的优先级错误,错误的或不存在的循环终止条件,遇到迭代发散时,不能终止循环,(4)是否有适当的错误处理通路,(5)边界测试,循环多一次或少一次,取值大一点或小一点,常见的单元测试方法有:,检查代码,代码排查Code Walkthroughs 代码审查Inspections,代码正确性证明,公式证明技术 自动定理证明,测试程序组件,测试对比验证Testingversus proving,选择测试用例Choosing Test Cases,完全测试,语句测试 分支测试,路径测试 用户定义路径测试,所有用途测试,全部谓词应用/部分计算应用测试,1.检查代码,由组件编码人本人自查,由一个审查小组审查,(1)代码排查Code Walkthroughs,编码人员将组件代码和相关文档提交给复审组,由复审组排查。,在排查期间,由编码人员介绍组件的设计思想和代码编写情况,引导复审组成员讨论。,讨论的气氛是非正式的,讨论的焦点是代码,而不是编码人。,排查是为了发现故障,不必要立即进行修改。,(2)代码审查Code Inspections,这种方法是Fagan(1976)在IBM提出来的,类似于排查,但更正规一些。,审查小组人员角色的选择:根据审查的目标,每个角色负责审查某一方面,审查小组按照事先准备的审查表的内容检查代码和文档。,小组召开全体会议,研讨对代码的总体看法和审查的目标,每个审查人员分别研究代码及相关文档,标记发现的故障,为第二次会议做准备,小组召开全体会议,审查人员报告审查结果,记录下各自发现的新故障,小组全体研究所有故障,确定哪些确实属于故障,哪些不属于故障。,代码排查和审查有效率:,组件的大部故障都可以通过代码排查和审查发现,Fagan通过实验得出:67%的系统错误可以在单元测试前通过代码审查发现。,Ackerman,Buchwald and Lewski指出在一个6000行的商业软件中全部错误的93%是通过代码审查发现的。,Jones广泛地研究了程序员的生产率,包括故障的性质及查找并修正故障的方法。查阅了 上一千万行的代码,发现故障总数的85%可以通过代码审查改正。,Jones研究的其他方法从未获得如此成功,没有一种技术能够除去一半以上的错误。,2.Proving Code Correct,应用数学方法证明组件的正确性。,当组件通过代码排查和代码审查后,,下一步测试是以更加结构化的方式详细审查,确保其正确性。,一种研究程序正确性方式是把代码看成语句的逻辑流。如果能够用一个正式的逻辑系统重写该程序,就能测试这种新的语句的正确性。,例如,用一系列断言和定理表示程序,能证明定理的正确性就能证明代码的正确性。,优点:比人工排查和审查更加严格,有利于发现代码中的算法故障。,缺点:证明需要花费更多的时间(例如,证明一个冒泡法排序的步骤要比组件的代码还要多)。,注意:,算法逻辑的正确性并不意味软件就正确,因此证明的意义是有限制的。,3.Choosing Test Cases 选择测试用例,测试用例:是用于测试一个程序的一组特殊输入数据。,测试是测试用例的有限集合。,选择好测试用例是测试成功的关键。,首先确定测试目的。根据测试目的选择测试用例,定义测试方案。,例如:测试求解方程ax,2,+by+c=0的程序,测试目的:测试运算功能,测试方法:黑盒测试法,划分等价类,测试用例:选择满足测试条件的典型数据,case1:输入三个实数 case5:a=2,b=0,c=1,case2:输入四个实数 case6:a=2,b=5,c=0,case3:输入两个实数 case7:a=5,b=2,c=3,case4:a=0,b=5,c=2 ,测试预期结果:每种用例的预期输出结果,5.6.3 集成测试,集成测试:,每个组件的单元测试都完成后,便可将其组装起来,称为集成测试,系统结构:,一个系统是一些组件按层次构造。,集成策略:,非渐增式测试:,全部组件一次集成,然后再测试,适合规模较小的系统,Big-bang,渐增式测试:,逐渐加入组件,一边加入一边测试,Bottom-up,Top-down,Sandwich,集成策略的影响:,集成测试的策略不同,集成所需的时间、编码的顺序、测试的用例、使用的工具、集成的成本都可能不同。,软件系统的层次体系结构,A,G,F,E,D,C,B,Test,E,Test,F,Test,D,G,Test,A,B,C,D,E,F,G,Test,C,Test,G,Test,B,E,F,1.Bottom-up Integration,集成方法:,先测试E,F,G。再将E、F与B组装起来,并测试;将G和D组装起来,并测试。最后将前两次组装的结果以及C和A组装起来,并测试。,辅助手段:,测试时需要编写“,驱动程序,”。,适用情况:,面向对象设计,重用组件,优点:,可以多人同时集成,一边设计,一边集成,缺点:,系统整体结构错误发现晚,Test A,Test,A,B,C,D,E,F,G,Test,A,B,C,D,2.Top-down Integration,集成方法:,先从顶层开始,逐渐向下扩展。,辅助手段:,测试时需要编写“,存根程序,”。,适用情况:,适合于Top-down设计,优点:,系统整体结构好,缺点:,可能需要编写大量存根程序,投入测试的人员数量受限制,Test,B,Test,C,Test,G,Test,A,B,C,D,E,F,G,Test,A,B,C,D,Test,D,Test,E,Test,A,Test F,3.Modified Top-down Integration,改进的自顶向下集成方法,分别测试A,B,C,D,集成A,B,C,D,分别测试E,F,G,集成A,G,Test,B,Test,D,Test,F,Test,A,B,C,D,E,F,G,Test,C,Test,E,Test,A,Test,G,4.Big Bang Integration(大爆炸集成),集成方法:,一次将全部组件都组装起来,然后再进行测试。,适应情况:,适用于小系统,Test E,Test F,Test,A,Test,A,B,C,D,E,F,G,Test,D,G,Test G,Test,B,E,F,5.Sandwich Integration,集成方法:,自顶向下与自底向上结合集成。,A,G,F,E,D,C,B,Test E,Test F,Test,A,Test,A,B,C,D,E,F,G,Test,D,G,Test G,Test,B,E,F,Test,C,Test,D,Test,B,6.Modified Sandwich Integration,5.6.4 确认测试,5.7 调试,5.8 软件可靠性,软件可靠性的定义,软件可靠性是软件在,给定的时间间隔,及,给定的环境条件,下,,按设计要求,,,成功地运行程序,的概率。,环境条件,指的是,软件的使用环境,。无论是什么软件,如果不对它的使用环境加以限制,都是会失效的。这种失效的数据,不能用来度量软件的可靠性。,规定的时间,在定义中,一般采用,“运行时间”t,作为时间的尺度。因,具体要处理的问题是多种多样的,其对应的输入环境是随机的;程序中相应程序路径的选取也是随机的;软件的失效也是随机的;应当把运行时间t当作随机变量来考虑。,规定的功能,在考虑软件可靠性时,首先应当明确,软件的功能是什么,,,哪些功能是主要的,,,哪些功能是次要的,。一般从软件需求分析说明书和设计说明书中可以了解这些情况。,由于功能不同,失效带来的损失就不一样。因此,还要明确,哪些失效是致命的,,,哪些失效是非致命的,,,哪些又是容易修复的,。此外,还要明确,,怎样才算是完成了一个规定的功能,。,成功地运行程序,是指不仅程序能正确地运行,满足用户对它的功能要求,而且当程序一旦受到意外的伤害,或系统故障时,能尽快恢复,仍能正常地运行。,测试中的可靠性分析,在软件开发的过程中,,利用测试的统计数据,估算软件的可靠性,,以控制软件的质量是至关重要的。,推测错误的产生频度,即推测错误产生的时间间隔,推测残留在程序中的错误数,评价测试的精确度和覆盖率,推测错误的产生频度,估算错误产生频度的一种方法是估算平均失效等待时间,MTTF,(,Mean Time To Failure,),MTTF,估算公式(Shooman模型),故障累积指数曲线模型,估算软件中故障总数,E,T,的方法,利用,Shooman模型,估算程序中原来错误总量,E,T,瞬间估算,解此方程组,利用最小二乘法进行程序原有错误数,E,T,及,K,的估算,由失效率,整理得,若对程序进行若干次不同的功能测试,可得到一系列实验数据,E,c,(,t,i,),(,t,i,),i,=1,2,n,令,有,用最小二乘法解此方程组,可解出,a,、,b,的估计值,最后得到,K,E,T,的估计值,利用植入故障法估算程序中原有故障总数,E,T,捕获再捕获抽样法,这种失效的数据,不能用来度量软件的可靠性。,输入(A,B,X),输出(A,B,X),再将E、F与B组装起来,并测试;,使用了未赋值或未初始化的变量,(2)分支测试branch testing,Bottom-up,Top-down,Sandwich,负整数,若把头注释看作是程序的概要,则外部文档则是对程序的详细介绍。,三个有效等价类:正整数,(1,1,1),(1,1,1),从各种角度测试(覆盖)组件的各种通路,当程序中判定多于一个时,形成的分支结构可以分为两类:嵌套型分支结构和连锁型分支结构。,a=5,b=3,c=4,公式证明技术 自动定理证明,错误推测法的基本想法是:列举出程序中所有可能有的错误和容易发生错误的特殊情况,根据它们选择测试用例。,设,N,s,是,在测试前人为地向程序中植入的故障数,,,n,s,是,经过一段时间测试后发现的播种故障数目,,,n,是,在测试中又发现的程序原有故障数,。设,测试用例发现植入故障和原有故障的能力相同,,则,程序中原有故障总数,N,(=,E,T,)估算值为,Hyman分别测试法,由两个测试员同时互相独立地测试同一程序的两个副本,用,t,表示,测试时间,,记,t,0,时,,程序中原有故障总数是,B,0,;,t,t,1,时,,测试员甲发现的故障总数是,B,1,;,测试员乙发现的故障总数是,B,2,;其中两人发现的,相同故障数目是,bc,;两人发现的,不同故障数目是,bi,。,在大程序测试时,头几个月两个测试员测试
展开阅读全文