《软件工程导论》(第6版)第7章 总体设计 复习笔记

第7章 实 现

一、编码

1.定义

编码是把软件设计结果翻译成用程序设计语言书写的程序,是对设计的进一步具体化,因此程序的质量主要取决于软件设计的质量。

2.选择程序设计语言

(1)重要性

①程序设计语言的特点必然会影响人的思维和解题方式。

②程序设计语言会影响人和计算机通信的方式和质量。

③程序设计语言会影响其他人阅读和理解程序的难易程度。

④所选用的程序设计语言的特点将对程序的可靠性、可读性、可测试性和可维护性产生深远的影响。

(2)适宜的程序设计语言的优点

①能使根据设计去完成编码时困难最少。

②可以减少需要的程序测试量。

③可以得出更容易阅读和更容易维护的程序。

(3)选择程序设计语言的理想标准

①选用高级语言编写写程序。

②选用的高级语言应该有理想的模块化机制,以及可读性好的控制结构和数据结构。

③选用语言特点应该使编译程序能够尽可能多地发现程序中的错误。

④选用的高级语言应该有良好的独立编译机制。

(4)选择程序设计语言的实用标准

①系统用户的要求

如果所开发的系统由用户负责维护,用户通常要求用他们熟悉的语言书写程序。

②可以使用的编译程序

运行目标系统的环境中可以提供的编译程序往往限制了可以选用的语言的范围。

③可以得到的软件工具

如果某种语言有支持程序开发的软件工具可以利用,则目标系统的实现和验证都变得比较容易。

④工程规模

如果工程规模很庞大,现有的语言又不完全适用,那么设计并实现一种供这个工程项目专用的程序设计语言,可能是一个正确的选择。

⑤程序员的知识

虽然对于有经验的程序员来说,学习一种新语言并不困难,但是要完全掌握一种新语言却需要实践。如果和其他标准不矛盾,那么应该选择一种已经为程序员所熟悉的语言。

⑥软件可移植性要求

如果目标系统将在几台不同的计算机上运行,或者预期的使用寿命很长,那么选择一种标准化程度高、程序可移植性好的语言就是很重要的。

⑦软件的应用领域

所谓的通用程序设计语言实际上并不是对所有应用领域都同样适用。

3.编码风格

源程序代码的逻辑简明清晰、易读易懂是好程序的一个重要标准,为了做到这一点,应该遵循下述规则。

(1)程序内部的文档

①定义

程序内部的文档包括恰当的标识符、适当的注解和程序的视觉组织等。

②命名规则

a.选取含义鲜明的名字,使它能正确地提示程序对象所代表的实体。

b.使用缩写时,缩写规则应该一致,并且应该给每个名字加注解。

③注释规则

a.在每个模块开始处应有序言性注解,简述功能、算法、接口、重要数据和开发简史。

b.程序中间应有一段与代码有关的注解,主要解释代码的必要性。

c.对于用高级语言书写的源程序,应该利用注解提供一些额外的信息。

d.应该用空格或空行清楚地区分注解和程序。

e.注解的内容一定要正确,错误的注解会妨碍对程序的理解。

④程序清单的布局规则

应利用适当的阶梯形式使程序的层次结构清晰明显。

(2)数据说明

虽然在设计期间已经确定了数据结构的组织和复杂程度,然而数据说明的风格却是在写程序时确定的。为了使数据更容易理解和维护,应该遵循的一些简单的原则如下:

①数据说明的次序应该标准化。有次序就容易查阅,因此能够加速测试、调试和维护的过程。

②多个变量名在一个语句中说明时,应该按字母顺序排列这些变量。

③使用复杂的数据结构,应用注解说明用设计语言实现这个数据结构的方法和特点。

(3)语句构造

①原则

设计期间确定了软件的逻辑结构,然而个别语句的构造却是编写程序的一个主要任务。构造语句时应该遵循的原则是,每个语句都应该简单而直接,不能为了提高效率而使程序变得过分复杂。

②使语句简单明了的规则

a.不要为了节省空间而把多个语句写在同一行。

b.尽量避免复杂的条件测试。

c.尽量减少对“非”条件的测试。

d.避免大量使用循环嵌套和条件嵌套。

e.利用括号使逻辑表达式或算术表达式的运算次序清晰直观。

(4)输入输出

在设计和编写程序时,输入输出风格需要遵循的规则:

①对所有输入数据都进行检验。

②检查输入项重要组合的合法性。

③保持输入格式简单。

④使用数据结束标记,不要要求用户指定数据的数目。

⑤明确提示交互式输入的请求,详细说明可用的选择或边界数值。

⑥当程序设计语言对格式有严格要求时,应保持输入格式一致。

⑦设计良好的输出报表。

⑧给所有输出数据加标志。

(5)效率

①定义

效率主要指处理机时间和存储器容量两个方面。

②原则

a.效率是性能要求,应该在需求分析阶段确定效率方面的要求。

b.效率是靠好设计来提高的。

c.效率和简单程度是一致的,不要牺牲程序的清晰性和可读性来不必要地提高效率。

③表现

a.程序运行时间

写程序的风格会对程序的执行速度和存储器要求产生影响。在把详细设计结果翻译成程序时,需要遵守以下规则:

第一,写程序之前先简化算术的和逻辑的表达式。

第二,仔细研究嵌套的循环,以确定是否有语句可以从内层往外移。

第三,尽量避免使用多维数组。

第四,尽量避免使用指针和复杂的表。

第五,使用执行时间短的算术运算。

第六,不要混合使用不同的数据类型。

第七,尽量使用整数运算和布尔表达式。在效率是决定性因素的应用领域,尽量使用有良好优化特性的编译程序,以自动生成高效目标代码。

b.存储器效率

第一,使用能保持功能域的结构化控制结构,是提高效率的好方法。

第二,在要求使用最少的存储单元时,应选用有紧缩存储器特性的编译程序。

第三,提高执行效率的技术能提高存储器效率。提高存储器效率的关键是“简单”。

c.输入输出的效率

第一,输入输出都应该有缓冲,以减少用于通信的额外开销。

第二,对二级存储器选用最简单的访问方法。

第三,二级存储器的输入输出应以信息组为单位进行。

第四,如果“超高效的”输入输出很难被人理解,则不应采用这种方法。

二、软件测试基础

1.软件测试的目标

(1)测试是为了发现程序中的错误而执行程序的过程。

(2)好的测试方案是极可能发现迄今为止尚未发现的错误的测试方案。

(3)成功的测试是发现了至今为止尚未发现的错误的测试。

(4)软件测试的根本目标是尽可能多地发现并排除软件中潜藏的错误,最终把一个高质量的软件系统交给用户使用。

注意:测试只能查找出程序中的错误,不能证明程序中没有错误。

2.软件测试准则

(1)所有测试都应该能追溯到用户需求。从用户的角度看,最严重的错误是导致程序不能满足用户需求的那些错误。

(2)应该远在测试开始之前就制定出测试计划。实际上,一旦完成了需求模型就可以着手制定测试计划,在建立了设计模型之后就可以立即开始设计详细的测试方案。因此,在编码之前就可以对所有测试工作进行计划和设计。

(3)应用Pareto原理,即测试发现的错误中80%可能是由程序20%的模块造成的。

(4)应该从“小规模”测试开始,并逐步进行“大规模”测试。首先重点测试单个程序模块,然后把测试重点转向在集成的模块簇中寻找错误,最后在整个系统中寻找错误。

(5)穷举测试是不可能的,即测试只能证明程序中有错误,不能证明程序中没有错误。

(6)为了达到最佳的测试效果,应该由独立的第三方从事测试工作。所谓“最佳效果”是指有最大可能性发现错误的测试。

3.测试方法

测试任何产品都有两种方法:如果已经知道了产品应该具有的功能,可以通过测试来检验是否每个功能都能正常使用;如果知道产品的内部工作过程,可以通过测试来检验产品内部动作是否按照规格说明书的规定正常进行。前一种方法称为黑盒测试,后一种方法称为白盒测试。

(1)白盒测试

白盒测试(结构测试)的前提是可以把程序看成装在一个透明的白盒子里,测试者完全知道程序的结构和处理算法。这种方法按照程序内部的逻辑测试程序,检测程序中的主要执行通路是否都能按预定要求正确工作。

(2)黑盒测试

黑盒测试(功能测试)把程序看作一个黑盒子,完全不考虑程序的内部结构和处理过程。黑盒测试是在程序接口进行的测试,只检查程序功能是否能按照规格说明书的规定正常使用,程序是否能适当地接收输入数据并产生正确的输出信息,程序运行过程中能否保持外部信息的完整性。

4.测试步骤

(1)模块测试

模块测试(单元测试)是把每个模块作为一个单独的实体来测试,检验其正确性。目的是保证每个模块作为一个单元能正确运行。模块测试所发现的是编码和详细设计的错误。

(2)子系统测试

子系统测试是把经过单元测试的模块放在一起形成一个子系统来测试。模块相互间的协调和通信是这个测试过程中的主要问题,即子系统测试着重测试模块的接口。

(3)系统测试

系统测试是把经过测试的子系统装配成一个完整的系统来测试。在这个过程不仅应该发现设计核编码的错误,还应该验证系统确实能提供需求说明书中指定的功能,而且系统动态特性也符合预定要求。系统测试发现的往往是软件设计中的错误,也可能发现需求说明中的错误。

注意:不论是子系统测试还是系统测试,都兼有检测和组装两重含义,都属于集成测试。

(4)验收测试

验收测试(确认测试)把软件系统作为单一的实体进行测试,它是在用户积极参与下进行的,而且主要使用实际数据进行测试。验收测试的目的是验证系统确实能够满足用户的需要,验收测试发现的是系统需求说明书中的错误。

(5)平行运行

平行运行就是同时运行新开发出来的系统和将被它取代的旧系统,以便比较新旧两个系统的处理结果。具体目的有如下几点:

①可以在准生产环境中运行新系统而又不冒风险。

②用户能有一段熟悉新系统的时间。

③可以验证用户指南和使用手册之类的文档。

④能够以准生产模式对新系统进行全负荷测试,可以用测试结果验证性能指标

5.测试阶段的信息流

图7-1 测试阶段的信息流

图7-1描绘了测试阶段的信息流,具体内容如下:

(1)输入信息

①软件配置

包括需求说明书、设计说明书和源程序清单等。

②测试配置

包括测试计划和测试方案。测试方案应包括测试时使用的输入数据(测试用例)、每组输入数据预定要检验的功能、每组输入数据预期应该得到的正确输出。测试配置是软件配置的一个子集,最终交出的软件配置应该包括上述测试配置以及测试的实际结果和调试的记录。

(2)调试

比较测试得出的实际结果和预期的结果,如果两者不一致则很可能是程序中有错误。设法确定错误的准确位置并且改正它,这就是调试的任务。与测试不同,通常由程序的编写者负责调试。

(3)收集和评价测试结果

在对测试结果进行收集和评价的时候,如果经常出现要求修改设计的严重错误,那么软件的质量和可靠性是值得怀疑的,应该进一步仔细测试。反之,如果看起来软件功能完成得很正常,遇到的错误也很容易改正,则仍然应该考虑两种可能:

①软件的可靠性是可以接受的;

②所进行的测试尚不足以发现严重的错误。

(4)软件可靠性模型

软件可靠性模型使用错误率数据估计将来出现错误的情况,并进而对软件可靠性进行预测。

 

三、单元测试(模块测试)

单元测试集中检测软件设计的最小单元—模块,它和编码属于软件过程的同一个阶段。在编写出源程序代码并通过了编译程序的语法检查之后,就可以用详细设计描述作指南,对重要的执行通路进行测试,以便发现模块内部的错误。单元测试主要使用白盒测试技术,而且对多个模块的测试可以并行地进行,包括人工测试和计算机测试两种。

1.测试重点

(1)模块接口

①模块接口的数据流是否能正常进出。

②参数的数目、次序、属性或单位系统与变元是否一致。

③是否修改了只作输入用的变元。

④全局变量的定义和用法在各个模块中是否一致。

(2)局部数据结构

对于模块来说,局部数据结构是常见的错误来源。应该仔细设计测试方案,以便发现局部数据说明、初始化、默认值等方面的错误。

(3)重要的执行通路

①选择最有代表性、最可能发现错误的执行通路进行测试。

②设计测试方案来发现由于错误计算、不正确的比较或不适当的控制流而造成的错误。

(4)出错处理通路

当评价出错处理通路时,应着重测试可能发生的错误为:

①对错误的描述是难以理解的。

②记下的错误与实际遇到的错误不同。

③在对错误进行处理之前,错误条件已经引起系统干预。

④对错误的处理不正确。

⑤描述错误的信息不足以帮助确定造成错误的位置。

(5)边界条件

边界测试是单元测试中最重要的任务。软件常常在它的边界上失效,例如,处理n元数组的第n个元素时,或做到1次循环中的第1次重复时,往往会发生错误。使用刚好小于、刚好等于和刚好大于最大值或最小值的数据结构、控制量和数据值的测试方案,非常可能发现软件中的错误。

2.测试方法

(1)代码审查

①定义

人工测试源程序可以由程序的编写者本人非正式地进行,也可以由审查小组正式进行。后者称为代码审查,是一种非常有效的程序验证技术。

②流程

a.组建审查小组。

审查小组由组长(能力强且没有参与任务的人员)、程序的设计者、程序的编写者、程序的测试者组成。

b.审查会议

第一,审查前,小组成员应该先研究设计说明书。

第二,审查会上由程序的编写者解释他是怎样用程序代码实现这个设计的。

第三,其他成员仔细倾听讲解并力图发现其中的错误。

第四,对照程序设计常见错误清单,分析审查程序并记录错误。

③优点

a.一次审查会上可以发现许多错误。

b.不需要每次发现一个错误就进行验证,减少了系统验证的总工作量。

④与计算机测试的关系

对于查找某些类型的错误来说,人工测试比计算机测试更有效;对于其他类型的错误来说则刚好相反。因此,人工测试和计算机测试是互相补充,相辅相成的,缺少其一都会使查找错误的效率降低。

(2)计算机测试

①方法

模块并不是一个独立的程序,因此必须要为每个单元测试开发驱动软件和(或)存根软件,具体如下:

a.驱动程序

接收测试数据,把这些数据传送给被测试的模块,并且印出有关的结果。

b.存根程序

代替被测试的模块所调用的模块,它使用被它代替的模块的接口,做最少量的数据操作,印出对入口的检验或操作结果,并且把控制归还给调用它的模块。

②例子

图7-2是一个正文加工系统的部分层次图,假定要测试其中编号为3.0的关键模块。

图7-2 正文加工系统的层次图

a.分析

第一,需要有一个测试驱动程序来调用它。这个驱动程序说明必要的变量,接收测试数据字符串,并且设置正文编辑模块的编辑功能。

第二,需要有存根程序简化地模拟下层模块。

b.设计

计算机测试所需要程序的伪码,如图7-3所示。

图7-3 计算机测试的程序

四、集成测试

1.概念

(1)方法分类

集成测试是测试和组装软件的系统化技术,由模块组装成程序时有两种方法:非渐增式方法和渐增式方法。

①非渐增式测试

先分别测试每个模块,再把所有模块按设计要求放在一起结合成所要的程序。

②渐增式测试

把下一个要测试的模块同已经测试好的那些模块结合起来进行测试,测试完以后再把下一个应该测试的模块结合进来测试,每次增加一个模块。渐增式测试同时完成单元测试和集成测试。

(2)非渐增式测试的缺点

①把所有模块放在一起,测试者面对的情况十分复杂。

②在庞大的程序中诊断定位一个错误非常困难。

③一旦改正一个错误之后,又会遇到新的错误,没有穷尽。

(3)渐增式测试的优点

①把程序划分成小段来构造和测试,比较容易定位和改正错误。

②对接口可以进行更彻底的测试。

③可以使用系统化的测试方法。

2.渐增式测试的策略

当使用渐增方式把模块结合到程序中去时,有自顶向下和自底向上两种集成策略。

(1)自顶向下集成

①定义

从主控制模块开始,沿着程序的控制层次向下移动,逐渐把各个模块结合起来。在把附属于主控制模块的模块组装到程序结构中时,使用深度优先的策略或宽度优先的策略。自顶向下集成方法是一个日益为人们广泛采用的测试核组装软件的途径。

②步骤

a.对主控制模块进行测试,测试时用存根程序代替所有直接附属于主控制模块的模块。

b.根据选的结合策略(深度优先或宽度优先),每次用一个实际模块代换一个存根程序。

c.在结合进一个模块的同时进行测试。

d.为了保证加入模块没有引进新的错误,可能需要进行回归测试。

③结合策略

图7-4 自顶向下结合

a.深度优先

深度优先的结合方法先组装在软件结构的一条主控制通路上的所有模块。步骤如下(参看图7-4):

第一,选择一条主控制通路取决于应用的特点(如,选取左通路)。

第二,结合模块M1、M2、M5

第三,把M8或M6结合进来。

第四,构造中央的和右侧的控制通路。

b.宽度优先

宽度优先的结合方法是沿软件结构水平地移动,把处于同一个控制层次上的所有模块组装起来。步骤如下(参看图7-4):

第一,结合模块M2、M3、M4

第二,结合下一个控制层次中的模块M5、M6、M7

第三,继续进行下去,直到所有模块都被结合进来为止。

(2)自底向上集成

①定义

自底向上测试从软件结构最低层的模块开始组装和测试。因为是从底部向上结合模块,总能得到所需的下层模块处理功能,所以不需要存根程序。

②自底向上结合的步骤

a.把低层模块组合成实现某个特定的软件子功能的族。

b.写一个用于测试的控制程序,协调测试数据的输入和输出。

c.对由模块组成的子功能族进行测试。

d.去掉驱动程序,沿软件结构自下向上移动,把子功能族组合起来形成大的子功能族。

③实例分析

图7-5 自底向上结合

图7-5描绘了自底向上的结合过程,分析如下:

a.把模块组合成族1、族2和族3。

b.使用驱动程序(图中用虚线方框表示)对每个子功能族进行测试。

c.族1和族2中的模块附属于模块Ma,去掉驱动程序D1和D2,把这两个族直接同Ma连接起来。同样在和模块Mb结合之前去掉族3的驱动程序D3

d.Ma和Mb这两个模块都与模块Mc结合起来。

3.两种集成策略的比较

(1)自顶向下集成

①优点

a.不需要测试驱动程序。

b.能够在测试阶段的早期实现并验证系统的主要功能。

c.能在早期发现上层模块的接口错误。

②缺点

a.需要存根程序,可能遇到与此相联系的测试困难。

b.低层关键模块中的错误发现较晚。

c.在早期不能充分展开人力。

(2)字底向上集成

①优点

a.不需要存根程序,不会遇到与存根程序相联系的测试困难。

b.能较早的发现低层关键模块的错误。

c.能在早期充分展开人力。

②缺点

a.需要测试驱动程序。

b.不能在测试阶段早期实现并验证系统的主要功能。

c.在早期不能发现上层模块的接口错误。

4.其他集成测试策略

在测试实际的软件系统时,应该根据软件的特点以及工程进度安排,选用适当的测试策略。一般说来,纯粹自顶向下或纯粹自底向上的策略可能都不实用,人们在实践中创造出许多混合策略。

(1)改进的自顶向下测试方法

基本上使用自顶向下的测试方法,但在早期使用自底向上的方法测试软件中的少数关键模块。缺点是测试关键模块时需要驱动程序。

(2)混合法

对软件结构中较上层使用的自顶向下方法与对软件结构中较下层使用的自底向上方法相结合。

5.回归测试

(1)定义

回归测试是指重新执行已经做过的测试的某个子集,以保证上述这些变化没有带来非预期的副作用。它可以用于保证由于调试或其他原因引起的变化,不会导致非预期的软件行为或额外错误的测试活动。

(2)方法

①通过重新执行全部测试用例的一个子集人工地进行。

②利用捕获回放工具,捕获测试用例和实际运行结果,然后回放,并比较运行结果。

(3)回归测试集

回归测试集(已执行过的测试用例的子集)包括下述3类不同的测试用例:

①检测软件全部功能的代表性测试用例。

②专门针对可能受修改影响的软件功能的附加测试。

③针对被修改过的软件成分的测试。

五、确认测试

1.概念

确认测试也称为验收测试,它的目标是验证软件的有效性。

(1)验证

验证指的是保证软件正确地实现了某个特定要求的一系列活动。

(2)确认

确认指的是为了保证软件确实满足了用户需求而进行的一系列活动。

(3)软件有效性

如果软件的功能和性能如同用户所合理期待的那样,软件就是有效的。

2.确认测试的范围

(1)要求

①必须有用户积极参与,或者以用户为主进行。用户应该参与设计测试方案,使用用户界面输入测试数据并且分析评价测试的输出结果。在验收之前由开发单位对用户进行培训。

②确认测试通常使用黑盒测试法。应该仔细设计测试计划和测试过程,测试计划包括要进行的测试的种类及进度安排,测试过程规定了用来检测软件是否与需求一致的测试方案。通过测试和调试要保证软件能满足所有功能要。

(2)结果

①功能和性能与用户要求一致,软件是可以接受的。

②功能和性能与用户要求有差距。

3.软件配置复查

(1)目的

复查的目的是保证软件配置的所有成分都齐全,质量符合要求,文档与程序完全一致,具有完成软件维护所必须的细节,而且已经编好目录。

(2)要求

①在确认测试过程中应该严格遵循用户指南及其他操作程序。

②必须仔细记录发现的遗漏或错误,并且适当地补充和改正。

4.Alpha和Beta测试

(1)Alpha测试

Alpha测试由用户在开发者的场所进行,并且在开发者对用户的“指导”下进行测试,且开发者负责记录发现的错误和遇到的问题。即Alpha测试是在受控的环境中进行的。

(2)Beta测试

①定义

Beta测试由软件的最终用户们在一个或多个客户场所进行。开发者通常不在Beta测试的现场,即Beta测试是软件在开发者不能控制的环境中的“真实”应用。

②测试过程

a.用户记录在Beta测试过程中遇到的问题,并且定期把这些问题报告给开发者。

b.开发者在接收到在Beta测试期间报告的问题之后,对软件产品进行必要的修改。

c.开发者向全体客户发布最终的软件产品。

六、白盒测试技术

设计测试方案是测试阶段的关键技术问题。所谓测试方案包括具体的测试目的,应该输入的测试数据和预期的结果。通常又把测试数据和预期的输出结果称为测试用例。其中最困难的问题是设计测试用的输入数据。

设计测试方案的基本目标是,确定一组最可能发现某个错误或某类错误的测试数据。已经研究出许多设计测试数据的技术,这些技术各有优缺点,没有哪一种是最好的,更没有哪一种可以代替其余所有技术;同一种技术在不同的应用场合效果可能相差很大,因此,通常需要联合使用多种设计测试数据的技术。

1.逻辑覆盖

(1)定义

逻辑覆盖是对一系列测试过程的总称,这组测试过程逐渐进行越来越完整的通路测试。

(2)分类

①语句覆盖

语句覆盖的含义是选择足够多的测试数据,使被测程序中每个语句至少执行一次。

②判定覆盖

判定覆盖(分支覆盖)含义是不仅每个语句必须至少执行一次,而且每个判定的每种可能的结果都应该至少执行一次。

③条件覆盖

条件覆盖的含义是不仅每个语句至少执行一次,而且使判定表达式中的每个条件都取到各种可能的结果。

④判定/条件覆盖

判定/条件覆盖的含义是选取足够多的测试数据,使得判定表达式中的每个条件都取到各种可能的值,而且每个判定表达式也都取到各种可能的结果。它同时满足判定覆盖和条件覆盖。

⑤条件组合覆盖

条件组合覆盖要求选取足够多的测试数据,使得每个判定表达式中条件的各种可能组合都至少出现一次。满足条件组合覆盖,也一定满足判定覆盖、条件覆盖和判定/条件覆盖标准。

⑥点覆盖

连通图G的子图G′是连通的,而且包含G的所有结点,则称G′是G的点覆盖。满足点覆盖标准要求选取足够多的测试数据,使得程序执行路径至少经过流图的每个结点一次,即点覆盖标准和语句覆盖标准是相同的。

⑦边覆盖

连通图G的子图G″是连通的,而且包含G的所有边,则称G″是G的边覆盖。为满足边覆盖的测试标准,要求选取足够多测试数据,使程序执行路径至少经过流图中每条边一次,即边覆盖与判定覆盖是相同的。

⑧路径覆盖

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

2.控制结构测试

(1)基本路径测试

①定义

基本路径测试是TomMcCabe提出的一种白盒测试技术。使用这种技术设计测试用例时,首先计算程序的环形复杂度,并用该复杂度为指南定义执行路径的基本集合,从该基本集合导出的测试用例可以保证程序中的每条语句至少执行一次,而且每个条件在执行时都将分别取真、假两种值。

②步骤

a.根据过程设计结果画出相应的流图。

b.计算流图的环形复杂度。

c.确定线性独立路径(至少包含一条在定义该路径之前不曾用过的边)的基本集合。

d.设计可强制执行基本集合中每条路径的测试用例。

注意:某些独立路径不能以独立的方式测试,即程序的正常流程不能形成独立执行该路径所需要的数据组合。

(2)条件测试

①关系表达式

一个简单条件是一个布尔变量或一个关系表达式,在布尔变量或关系表达式之前还可能有一个NOT(┐)算符。关系表达式的形式如下:

E1<关系算符>E2

其中,E1和E2是算术表达式,而<关系算符>是下列算符之一:<,≤,=,≠,>或≥。复合条件由两个或多个简单条件、布尔算符和括弧组成。布尔算符有OR(∣),AND(&)和NOT(┐)。不包含关系表达式的条件称为布尔表达式。

②条件错误的类型

a.布尔算符错;

b.布尔变量错;

c.布尔括弧错;

d.关系算符错;

e.算术表达式错。

③条件测试的优点

a.容易度量条件的测试覆盖率。

b.程序内条件的测试覆盖率可指导附加测试的设计。

④条件测试的目的

条件测试的目的不仅是检测程序条件中的错误,而且是检测程序中的其他错误。

⑤条件测试策略

a.分支测试

对于复合条件C来说,C的真分支和假分支以及C中的每个简单条件,都应该至少执行一次。域测试要求对一个关系表达式执行3个或4个测试。包含n个变量的布尔表达式需要2n个测试。

b.BRO测试

BRO测试利用条件C的条件约束来设计测试用例。包含n个简单条件的条件C的条件约束定义为(D1,D2,…,Dn),其中Di(0<i<n)表示条件C中第i个简单条件的输出约束。对于布尔变量B来说,B的输出约束指出,B必须是真(t)或假(f);对于关系表达式来说,用符号>,=和<指定表达式的输出约束。

(3)循环测试

①定义

循环是绝大多数软件算法的基础,但是,在测试软件时却往往未对循环结构进行足够的测试。循环测试是一种白盒测试技术,它专注于测试循环结构的有效性

②分类

在结构化的程序中通常只有3种循环,即简单循环、串接循环和嵌套循环。

图7-6 三种循环

a.简单循环

结构如图7-6(a)所示。

b.嵌套循环

结构如图7-6(b)所示。可以通过以下步骤减少测试数:

第一,从最内层循环开始测试,把所有其他循环都设置为最小值。

第二,对最内层循环使用简单循环测试方法。使内层循环的迭代参数取最小值,并为越界值或非法值增加一些额外的测试。

第三,由内向外,对下一个循环进行测试,但保持所有其他外层循环为最小值,其他嵌套循环为“典型”值。

第四,继续进行下去,直到完成所有循环。

c.串接循环

结构如图7-6(c)所示。如果串接循环的各个循环都彼此独立,则可以使用前述的测试简单循环的方法来测试串接循环;循环不独立时,使用测试嵌套循环的方法来测试串接循环。

七、黑盒测试技术

1.概念

黑盒测试着重测试软件功能。黑盒测试并不能取代白盒测试,它是与白盒测试互补的测试方法,它很可能发现白盒测试不易发现的其他类型的错误。

(1)目的

黑盒测试力图发现下述类型的错误:

①功能不正确或遗漏了功能。

②界面错误。

③数据结构错误或外部数据库访问错误。

④性能错误。

⑤初始化和终止错误。

(2)适用性

白盒测试在测试过程的早期阶段进行,黑盒测试主要用于测试过程的后期。

(3)设计测试方案需要考虑的问题

①怎样测试功能的有效性?

②哪些类型的输入可构成好测试用例?

③系统是否对特定的输入值特别敏感?

④怎样划定数据类的边界?

⑤系统能够承受什么样的数据率和数据量?

⑥数据的特定组合将对系统运行产生什么影响?

(4)测试用例的标准

①能够减少为达到合理测试所需要设计的测试用例的总数。

②能够告诉人们,是否存在某些类型的错误,而不是仅仅指出与特定测试相关的错误是否存在。

2.技术方法

(1)等价划分

①定义

等价划分是一种黑盒测试技术,这种技术把程序的输入域划分成若干个数据类,据此导出测试用例。一个理想的测试用例能独自发现一类错误。

②目的

等价划分法力图设计出能发现若干类程序错误的测试用例,从而减少必须设计的测试用例的数目。

③流程

a.划分数据的等价类

第一,需要研究程序的功能说明,从而确定输入数据的有效等价类和无效等价类。

第二,在确定输入数据的等价类时常常还需要分析输出数据的等价类。

第三,在划分等价类时还应考虑编译程序的检错功能。

b.根据等价类设计测试方案

第一,设计一个新的测试方案以尽可能多地覆盖尚未被覆盖的有效等价类,重复这一步骤直到所有有效等价类都被覆盖为止。

第二,设计一个新的测试方案,使它覆盖一个而且只覆盖一个尚未被覆盖的无效等价类,重复这一步骤直到所有无效等价类都被覆盖为止。

注意:通常程序发现一类错误后就不再检查是否还有其他错误,因此,应该使每个方案只覆盖一个无效的等价类。

④等价类划分规则

a.如果规定了输入值的范围,则可划分一个有效的等价类(输入值在此范围内),两个无效的等价类(输入值小于最小值或大于最大值)。

b.如果规定了输入数据的个数,则类似地也可以划分出一个有效的等价类和两个无效的等价类。

c.如果规定了输入数据的一组值,而且程序对不同输入值做不同处理,则每个允许的输入值是一个有效的等价类,此外还有一个无效的等价类(任一个不允许的输入值)。

d.如果规定了输入数据必须遵循的规则,则可以划分出一个有效的等价类(符合规则)和若干个无效的等价类(从各种不同角度违反规则)。

e.如果规定了输入数据为整型,则可以划分出正整数、零和负整数3个有效类。

f.如果程序的处理对象是表格,则应该使用空表,以及含一项或多项的表。

(2)边界值分析

使用边界值分析方法设计测试方案首先应该确定边界情况,选取的数据应该刚好等于、稍小于和稍大于等价类边界值,即应该选取刚好等于、稍小于和稍大于等价类边界值的数据作为测试数据,而不是选取每个等价类内的典型值或任意值作为测试数据。

(3)错误推测

①定义

错误推测法基本思想是列举出程序中可能有的错误和容易发生错误的特殊情况,并且根据它们选择测试方案。

②输入组合

a.定义

输入组合是综合考虑各个输入数据相结合产生的测试功效,减少遗漏输入数据易于出错的情况。

b.选择途径

第一,利用判定表或判定树为工具,列出输入数据各种组合与程序应作的动作之间的对应关系,然后为判定表的每一列至少设计一个测试用例。

第二,把计算机测试和人工检查代码结合起来。

八、调试

1.定义

调试(纠错)作为成功测试的后果出现,即调试是在测试发现错误之后排除错误的过程。调试是把症状和原因联系起来的尚未被人深入认识的智力过程。

2.调试过程

(1)流程

图7-7 调试过程

如图7-7所示,调试过程从执行一个测试用例开始,评估测试结果,如果发现实际结果与预期结果不一致,表明在软件中存在着隐藏的问题。调试过程试图找出产生症状的原因,以便改正错误。

(2)调试的结果

①找到了问题的原因并把问题改正和排除掉了。

②没找出问题的原因。

没找出问题的原因时,调试人员可以猜想一个原因,并设计测试用例来验证,重复这个过程直至找到原因并改正了错误。

(3)软件错误的特征

①症状和产生症状的原因可能在程序中相距甚远。

②当改正了另一个错误之后,症状可能暂时消失了。

③症状可能实际上并不是由错误引起的。

④症状可能是由不易跟踪的人为错误引起的。

⑤症状可能是由定时问题而不是由处理问题引起的。

⑥可能很难重新产生完全一样的输入条件。

⑦症状可能时有时无。

⑧症状可能是由分布在许多任务中的原因引起的,这些任务运行在不同的处理机上。

3.调试途径

(1)蛮干法

①基本思路

按照“让计算机自己寻找错误”的策略,这种方法印出内存的内容,激活对运行过程的跟踪,并在程序中到处都写上WRITE(输出)语句,在生成的信息海洋的某个地方发现错误原因的线索。

②适用性

蛮干法是寻找软件错误原因的最低效的方法。仅当所有其他方法都失败了的情况下,才应该使用这种方法。

(2)回溯法

①基本思路

从发现症状的地方开始,人工沿程序的控制流往回追踪分析源程序代码,直到找出错误原因为止。

②适用性

当调试小程序时回溯法非常有效的。但随着程序规模的扩大,应该回溯的路径数目也变得越来越大,以至彻底回溯变成完全不可能了。

(3)原因排除法

①对分查找法

如果已经知道每个变量在程序内若干个关键点的正确值,可用赋值语句或输入语句在程序中点附近“注入”这些变量的正确值,然后运行程序并检查所得到的输出。如果输出结果是正确的,则错误原因在程序的前半部分;反之,错误原因在程序的后半部分。对错误部分重复使用这个方法,直到把出错范围缩小到容易诊断的程度为止。

②归纳法

归纳法是从个别现象推断出一般性结论的思维方法。使用这种方法调试程序时,首先把和错误有关的数据组织起来进行分析。然后导出对错误原因的一个或多个假设,并利用已有的数据来证明或排除这些假设。

③演绎法

演绎法从一般原理或前提出发,经过排除和精化的过程推导出结论。采用这种方法调试程序时,首先设想出所有可能的出错原因,然后用测试来排除每一个假设的原因。

4.调试准则

(1)仔细分析程序出错处的逻辑模式,找出该错误出现的所有地方。

(2)在改正错误前应仔细研究源程序,以评估逻辑和数据结构的耦合程度。

(3)修改软件产品的同时改进开发软件产品的软件过程,避免今后在程序中出现错误。

九、软件可靠性

1.基本概念

测试阶段的根本目标是消除错误,保证软件的可靠性。

(1)软件可靠性

软件可靠性是程序在给定的时间间隔内,按照规格说明书的规定成功地运行的概率。

(2)软件的可用性

软件可用性是程序在给定的时间点,按照规格说明书的规定,成功地运行的概率。

(3)比较

①可靠性意味着在0到t这段时间间隔内系统没有失效。

②可用性只意味着在时刻t,系统是正常运行的。

(4)MTTF和MTTR

①概念

a.平均维修时间MTTR

表示修复一个故障平均需要用的时间,取决于维护人员的技术水平和对系统的熟悉程度,也和系统的可维护性有重要关系。

b.平均无故障时间MTTF

表示系统按规格说明书规定成功地运行的平均时间,主要取决于系统中潜伏的错误的数目,因此和测试的关系十分密切。

②计算公式

如果在一段时间内,软件系统故障停机时间分别为td1,td2,…,正常运行时间分别为tu1,tu2,…,则系统的稳态可用性为:

其中:

(7.1)式可以变成

2.估算平均无故障时间的方法

(1)符号

①ET:测试之前程序中错误总数;

②IT:程序长度(机器指令总数);

③τ:测试(包括调试)时间;

④Ed(τ):在0至τ期间发现的错误数;

⑤Ec(τ):在0至τ期间改正的错误数。

(2)基本假定

①单位长度里的错误数ET/IT近似为常数。通常0.5×102≤ET/IT≤2×102

②失效率正比于软件中潜藏的错误数,平均无故障时间MTTF与剩余的错误数成反比。

③假设发现的每一个错误都立即正确地改正了,即Ec(τ)= Ed(τ)。

a.剩余的错误数

b.单位长度程序中剩余的错误数

(3)估算平均无故障时间

①平均无故障时间与单位长度程序中剩余的错误数成反比(K经典值为200),即

②估算平均无故障时间的公式,可以评价软件测试进展情况。由(7.5)式可得:

(4)估计错误总数的方法

①植入错误法

a.基本思路

测试之前,由专人在程序中随机地植入一些错误;测试之后,根据发现的错误中原有的和植入的两种错误的比例,来估计程序中原有错误的总数E。

b.计算方法

假设人为地植入的错误数为Ns,经过一段时间的测试之后发现ns个植入的错误,还发现了n个原有的错误。则估计出程序中原有错误的总数为:

其中即是错误总数ET的估计值。

②分别测试法

a.基本思路

假定所用的测试方案发现植入错误和发现原有错误的概率相同。

b.计算方法

在测试过程的早期阶段,由测试员甲和测试员乙分别测试同一个程序的两个副本,由另一名分析员分析他们的测试结果。用r表示测试时间,假设:

第一,τ=0时错误总数为B0

第二,r=τ1时测试员甲发现的错误数为B1

第四,τ=τ1时测试员乙发现的错误数为B2

第五,τ=τ1时两个测试员发现的相同错误数为bc

假定测试员乙发现有标记错误和发现无标记错误的概率相同,则可以估计出测试前程序中的错误总数为:

  • 12
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值