198.实现

第7章  实现程序员

 

实现:编码和测试的统称。算法

编码:把软件设计结果翻译成用某种程序设计语言书写的程序。数据库

 

程序的质量主要取决于:小程序

• 软件设计的质量。数组

• 所选用的程序设计语言的特色及编码风格也将对程序的可靠性、可读性、可测试性和可维护性产生深远的影响。数据结构

• 软件测试也是保证软件质量的关键步骤,它是对软件规格说明、设计和编码的最后复审。函数

 

 

7.1  编码  

7.1.1  选择程序设计语言

• 编码以前的一项重要工做:工具

     就是选择一种适当的程序设计语言。布局

• 高级语言post

    用高级语言写的程序容易阅读,容易测试,容易调试,容易维护。

 

选用高级语言的实用标准:

(1) 系统用户的要求。选择用户熟悉的语言。

(2) 可使用的编译程序。运行目标系统的环境中可提供的编译程序每每限制了所选用语言的范围。

(3) 能够获得的软件工具。某种语言是否有支持程序开发的软件工具能够利用。

(4) 工程规模。

(5) 程序员的知识。应该选择一种已经为程序员所熟悉的语言。

(6) 软件可移植性要求。

(7) 软件的应用领域。

 

7.1.2  编码风格

好程序的标准:

    代码的逻辑:简明清晰、易读易懂。

故编码应该遵循下述规则:

• 程序内部的文档

• 数听说明

• 语句构造

• 输入输出

• 效率

•  程序内部的文档

 

程序内部的文档包括:恰当的标识符、适当的注解

和程序的视觉组织等。

•                含义鲜明的名字

•                正确的注解

•                缩写规则一致

    程序清单的布局对于程序的可读性也有很大影

响,应该利用适当的阶梯形式使程序的层次结构

清晰明显。

 

 

2.  数听说明

•数听说明的次序应该标准化。

     有次序就容易查阅,所以可以加速测试、调试和维护的过程。

        先按类型

        再按字母

•复杂的数据结构,应该用注解说明用程序设计语言实现这个数据结构的方法和特色。

 

 

3. 语句构造

•简单而直接

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

尽可能避免使用复杂的条件;

尽可能减小使用“非”条件;

避免大量使用循环嵌套和条件嵌套;

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

 

4. 输入输出

•对全部输入数据都进行检验;

•检查输入项重要组合的合法性;

•保持输入格式简单;

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

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

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

•设计良好的输出报表;

•给全部输出数据加标志。

 

5.  效率

主要讨论程序运行时间和输入输出对效率的影响。

(1) 输入输出的效率

     简单清晰是提升人机通信效率的关键。

     如输入输出很难被人理解,将下降效率。

(2) 程序运行时间

影响源程序的效率的因素:

•算法的效率;

•写程序的风格。(对程序的执行速度和存储器要求产生影响)

所以写程序时可应用下述规则:

 

写程序时可应用下述规则:

•写程序以前先简化算术的和逻辑的表达式;

•仔细研究嵌套的循环,以肯定是否有语句能够从内层往外移;

•尽可能避免使用多维数组;

•尽可能避免使用指针和复杂的表;

•使用执行时间短的算术运算;

•不要混合使用不一样的数据类型;

•尽可能使用整数运算和布尔表达式。

 

为何要有编码规范

编码规范对于程序员而言尤其重要,缘由:

• 一个软件的生命周期中,80%的花费在于维护;

•几乎没有任何一个软件,在其整个生命周期中,均由最初的开发人员来维护;

•编码规范能够改善软件的可读性,可让程序员尽快而完全地理解新的代码。

    为了执行规范,每一个软件开发人员必须一致遵照编码规范。

 

7.2  软件测试基础

7.2.1  软件测试的目标

G.Myers给出了关于测试的一些规则,这些规则也能够看做是测试的目标或定义。

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

(2) 好的测试方案是很可能发现迄今为止还没有发现的错误的测试方案;

(3) 成功的测试是发现了至今为止还没有发现的错误的测试。

  测试是在精心控制的环境下执行程序,以发现程序中的错误,给出程序可靠性的鉴定。

 

7.2.1  软件测试的目标

•测试的正肯定义是:“为了发现程序中的错误而执行程序的过程”。

•错误的认识:

    “测试是为了代表程序是正确的”,

    “成功的测试是没有发现错误的测试” 。

•正确认识测试的目标是十分重要的,测试目标决定了测试方案的设计。

    若是为了代表程序的正确,就会设计一些不易暴露错误的测试方案;

    若是是为了发现程序中的错误,就会设计出最能暴露错误的测试方案。

7.2.2  软件测试准则

(1) 全部测试都应该能追溯到用户需求。

    软件测试的目标是发现错误,最严重的错误是致使程序不能知足用户需求。

(2) 应该远在测试开始以前就制定出测试计划。

    在完成需求模型时,就着手制定测试计划,

    在创建了设计模型后,就开始设计详细的测试方案。

(3) 应该从“小规模”测试开始,并逐步进行“大规模”测试。

    先测试单个程序模块,再测试集成模块,最后在整个系统中寻找错误。

(4) 应该由独立的第三方从事测试工做。

    软件工程师不能承担所有测试工做,主要承担模块测试工做。

(5) 穷举测试是不可能的。

穷举测试:把程序全部可能的执行路径都检查一遍的测试。

    即便是一个中等规模的程序,其执行路径的排列数也十分庞大。所以,测试只能证实程序中有错误,不能证实程序中没有错误。

 

• 假设一个程序P有输入量XY及输出量Z。在字长为32位的计算机上运行。若XY取整数,按黑盒方法进行穷举测试:

 

• 可能采用的

  测试数据组:

    232×232

     264  

•若是测试一组数据须要1毫秒,一年工做365×24小时,完成全部测试需5亿年。

 

 

7.2.3  测试方法

•黑盒测试:指在软件界面上进行的测试。通常用来证明软件功能的可操做性;证明能很好的接收输入,并正确地产生输出;以及证明对外部信息完整性的保持。

 

•白盒测试:对程序细节进行严密检验,对软件的逻辑路径进行测试。

 

黑盒测试法:把程序看做一个黑盒子,彻底不考虑程序的内部结构和处理过程。只检查程序功能是否按照规格说明书的规定正常使用。

黑盒测试又称为功能测试。

 

白盒测试法:把程序当作装在一个透明的白盒子里,测试者彻底知道程序的结构和处理算法,用于检测程序中的主要执行通路是否都能按预约要求正确工做。

白盒测试又称为结构测试。

 

7.2.4  测试步骤

1. 模块测试

    把每一个模块做为一个单独的实体来测试。

    模块测试一般又称为单元测试。在测试中所发现的每每是编码和详细设计的错误。

 

2. 子系统测试

    把通过单元测试的模块放在一块儿造成一个子系统来测试。

    模块相互间的协调和通讯是这个测试过程当中的主要问题,着重测试模块的接口。

 

3. 系统测试

    把通过测试的子系统装配成一个完整的系统来测试。

    验证系统可否提供需求说明书中指定的功能,动态特性是否符合预约要求。其中发现的每每是软件设计中的错误,也多是需求说明中的错误。

    子系统测试和系统测试,都兼有检测和组装两重含义,一般称为集成测试。

 

4. 验收测试

    把软件系统做为单一的实体进行测试,测试内容与系统测试基本相似,但它是在用户积极参与下进行的,并且主要使用实际数据进行测试。

    目的是验证系统确实可以知足用户的须要,其中发现的每每是系统需求说明书中的错误。

    验收测试也称为确认测试。

 

5. 平行运行

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

这样作的具体目的有以下几点:

(1) 能够在准生产环境中运行新系统而又不冒风险;

(2) 用户能有一段熟悉新系统的时间;

(3) 能够验证用户指南和使用手册之类的文档;

(4) 可以以准生产模式对新系统进行全负荷测试,进一步验证性能指标。

 

7.2.5  测试阶段的信息流

测试阶段的的输入信息有两类:

 (1)软件配置,包括需求说明书、设计说明书和源程序清单等;

(2)测试配置,包括测试计划和测试方案。

测试方案包括:

•测试用例:测试时使用的输入数据;

•每组输入数据预约要检验的功能,以及每组输入数据预期应该获得的正确输出。

    图7.1

    测试结果和预期结果不一致,程序中可能有错误,进入调试阶段。由程序的编写者负责调试。

 

图7.1 测试阶段的信息流

 

•若是常常出现要求修改设计的严重错误,那么软件的质量和可靠性是值得怀疑的。

 

•若是软件功能完成得很正常,遇到的错误也很容易改正,仍然应该考虑两种可能:

 (1)软件的可靠性是能够接受的;

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

 

•若是通过测试,一个错误也没有被发现,则极可能是对测试配置思考不充分,以至不能暴露软件中潜藏的错误。

 

 

7.3  单元测试

    单元测试主要使用白盒测试技术,并且对多个模块的测试能够并行地进行。

 

7.3.1  测试重点

1. 模块接口

    首先应该对经过模块接口的数据流进行测试,若是数据不能正确地进出,全部其余测试都是不切实际的。

2. 局部数据结构

   局部数听说明、初始化、默认值等方面是否正确。

3. 重要的执行通路

   因为不可能进行穷尽测试,在单元测试期间选择最有表明性、最可能发现错误的执行通路进行测试。

4. 出错处理通路

    好的设计应该能预见出现错误的条件,而且设置适当的处理错误的通路。

    应该认真测试这种通路可否正确运行。

5. 边界条件

    边界测试在单元测试中很是重要。软件经常在它的边界上失效。

    使用恰好小于、恰好等于和恰好大于最大值或最小值的测试方案,很是可能发现软件中的错误。

 

测试的过程

•程序的测试通常按三种方式进行:

静态分析

动态测试

自动测试

 

•测试的过程,先进行静态分析,而后进行动态测试;在某些特殊状况下,也能够借助自动测试工具对程序进行查错。

•静态分析:是指不执行程序,而只由人工对程序文本进行检查,经过阅读和讨论,分析和发现程序中的错误。

•静态分析是一种卓有成效的测试方法,大约30%—70%的逻辑设计错误和编码错误能够经过静态分析检查出来。又称代码审查。

 

7.3.2  代码审查

•讨论:是由一些有经验的测试人员阅读程序文本及有关文档,对程序的结构与功能、数据的结构、接口、控制流以及语法进行讨论和分析,从而揭示程序中的错误。

•走查:是由测试人员用一些测试用例沿程序逻辑运行,并随时记录程序的踪影;而后进行分析,发现程序中的错误。

 

测试的过程

•程序的动态分析:

   使用测试用例在计算机上运行程序,使程序在运行过程当中暴露错误。

•自动测试工具:

   是人们编制的用于测试的软件,并用它来代替人工测试。

 

7.3.3  计算机测试

    模块并非一个独立的程序,所以必须为每一个单元测试开发驱动软件和(或)存根软件。

•驱动程序:也称“主程序”,它接收测试数据,把这些数据传送给被测试的模块,而且印出有关的结果。

•存根程序:也称“虚拟子程序”,代替被测试的模块所调用的模块。

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

 

对最小的软件设计单元——模块的验证工做

 

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

 

•须要有一个测试驱动程序来调用它。

    说明必要的变量,接收测试数据——字符串,而且设置正文编辑模块的编辑功能。

•存根程序简化地模拟下层模块,完成具体的编辑功能。可只用一个存根程序模拟正文编辑模块的全部下层模块。

 

图7.2 正文加工系统的层次图

 

 

代码审查比计算机测试优越之处:

•一次审查会上能够发现许多错误;

•用计算机测试的方法发现错误以后,一般须要先改正这个错误才能继续测试,所以错误是一个一个地发现并改正的。

 

    人工测试和计算机测试互相补充,相辅相成,缺乏其中任何一种方法都会使查找错误的效率下降。

 

7.4  集成测试

集成测试:把模块按照设计要求组装起来的同时进行测试。

主要目标:是发现与接口有关的问题。与系统测试相似。

 

组装模块有两种方法:

1.非渐增式测试(总体拼装):

  首先对每一个模块分别进行模块测试,而后再把全部模块组装在一块儿进行测试,最终获得要求的软件系统;

 

 

 

 

2.渐增式测试(增量集成):

•首先对一个个模块进行模块测试,而后将这些模块逐步组装成较大的系统;

•在组装的过程当中边链接边测试,以发现链接过程当中产生的问题

•经过增殖逐步组装成为要求的软件系统。

 

 

两种方法优缺点:

非渐增式测试:

    一会儿把全部模块放在一块儿,并把庞大的程序做为一个总体来测试,测试者面对的状况十分复杂,会遇到许多错误,改正错误更是极端困难。并且改正一个错误以后,立刻又会遇到新的错误。

渐增式测试:

    它把程序划分红小段来构造和测试,比较容易定位和改正错误;对接口能够进行更完全的测试。

    故广泛采用渐增式测试方法。

    当使用渐增方式组装模块时,有自顶向下和自底向上两种集成策略。

 

7.4.1  自顶向下集成

•将模块按系统程序结构,沿控制层次自顶向下进行组装。从主控制模块开始。

 

•在测试过程当中较早地验证了主要的控制和判断点。

 

•选用按深度方向测试的方式,能够首先实现和验证一个完整的软件功能。

   

• 或使用深度优先策略,或使用宽度优先策略。

 

 

 

7.4.1  自顶向下集成

由下述4个步骤完成:

第一步,对主控制模块进行测试,测试时用存根程序代替全部直接附属于主控制模块的模块;

第二步,根据选定的结合策略(深度优先或宽度优先),每次用一个实际模块代换一个存根程序;

第三步,在结合进一个模块的同时进行测试;

第四步,为了保证加入模块没有引进新的错误,须要进行回归测试(所有或部分地重复之前作过的测试)。

上述第二步到第四步实质上构成了一个循环.

 

 

图7.3 自顶向下宽度优先结合

7.4.2  自底向上集成

•从程序模块结构的最底层的模块( 原子模块)开始组装和测试。

•由于是自底向上组装模块,对于一个给定层次的模块,它的子模块已经组装并测试完成,因此再也不须要存根程序。在测试过程当中须要从子模块获得的信息能够直接运行子模块获得。

 

 

用下述四个步骤完成:

第一步,把低层模块组合成实现某个特定的软件子功能的族;

第二步,写一个驱动程序,协调测试数据的输入和输出;

第三步,对由模块组成的子功能族进行测试;

第四步,去掉驱动程序,沿软件结构自下向上移动,把子功能族组合起来造成更大的子功能族。

上述第二步到第四步实质上构成了一个循环。图7.4

 若是软件结构的顶部两层用自顶向下的方法组装,能够明显减小驱动程序的数目,并且族的结合也将大大简化。

 

图7.4 自底向上结合

7.4.3  不一样集成测试策略的比较

     自顶向下测试方法的优势:

•不须要测试驱动程序,

•可以在测试阶段的早期实现并验证系统的主要功能,

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

 

     自顶向下测试方法的缺点:

•是须要存根程序,

•低层关键模块中的错误发现较晚,

•用这种方法在早期不能充分展开人力。

    自底向上优缺点与自顶向下恰好相反。

 

一般采用混合策略:

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

•基本上使用自顶向下的测试方法,

•早期,对少数关键模块使用自底向上的测试方法。

 

优势:

•具有自顶向下方法的优势;

•能在测试的早期发现关键模块中的错误;

 

缺点:

•测试关键模块时须要驱动程序。

 

(2) 混合法。

•较上层使用的自顶向下方法;

•较下层使用的自底向上方法。

兼有两种方法的优势和缺点,最好的折衷方法。

 

7.4.4  回归测试

    在集成测试过程当中每当一个新模块结合进来时,程序就发生了变化,这些变化有可能使原来工做正常的功能出现问题。

回归测试:从新执行已经作过测试的某个子集,以保证上述这些变化没有带来非预期的反作用。

 

7.5  确认测试

也称为验收测试。

目标:验证软件的有效性。发现那些只有最终用户才能发现的错误。

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

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

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

软件有效性的标准:需求分析阶段产生的软件需求规格说明书,它是确认测试的基础。

 

•Alpha测试

    由一个用户在开发者的场所来进行的测试,软件在开发者对用户的指导下进行测试,开发者负责记录错误和使用中出现的问题。

•Beta测试

    由软件的最终用户在一个或者多个用户场所来进行,开发者不在场,用户记录问题。

 

7.6  白盒测试技术

设计测试方案是测试阶段的关键技术问题。

测试方案:

•包括测试目的(预约要测试的具体功能),

•应该输入的测试数据和预期的结果。

测试用例:由测试输入数据及与之对应的输出结果组成。

•测试用例设计的好坏直接决定了测试的效果和结果。所以在软件测试活动中最关键的步骤就是设计有效的测试用例。(由于不可能进行穷尽的测试)

•测试用例能够针对黑盒测试设计用例,也能够针对白盒测试设计用例。

 

白盒测试技术:用白盒方法测试软件时设计测试数据的典型技术。

黑盒测试技术:用黑盒方法测试软件时设计测试数据的典型技术。

 

白盒测试的目的:

• 保证一个模块中的全部独立路径至少被执行一次;

•对全部的逻辑值均须要测试真、假两个分支;

•在上下边界及可操做范围内运行全部循环;

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

 

白盒测试的主要方法

• 逻辑驱动测试(逻辑覆盖)

• 基本路径测试

      

 主要用于软件验证。

 用程序设计的控制结构导出测试用例。

 

7.6.1  逻辑覆盖

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

覆盖:测试数据执行源程序的过程。

 

覆盖源程序语句的详尽程度存在不一样的覆盖标准:

•语句覆盖

•断定覆盖

•条件覆盖

•断定/条件覆盖

•条件组合覆盖

 

例:图7.5所示的程序流程图描绘了一个被测模块的处理算法。

   

图7.5 被测试模块的流程图

 

1. 语句覆盖

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

    为了使每一个语句都执行一次,程序的执行路径应该是sacbed。

    须要输入下面的测试数据:

    A=2,B=0,X=4( X能够是任意实数)

 

语句覆盖缺点:

•对程序的逻辑覆盖不多;

•语句覆盖只关心断定表达式的值;

•没有分别测试断定表达式中每一个条件取不一样值时的状况。

语句覆盖是很弱的逻辑覆盖标准。

 

2. 断定覆盖

又叫分支覆盖。

含义:不只每一个语句必须至少执行一次,并且每一个断定的每一个分支都至少执行一次。

须要输入下面的测试数据:

    A=3,B=0,X=3(1)    (路径是:sacbd)

    A=2,B=1,X=1    (路径是:sabed)

    断定覆盖比语句覆盖强,可是对程序逻辑的覆盖程度仍然不高,只覆盖了程序所有路径的一半。

还差: sacbed,sabd

 

3. 条件覆盖

含义:不只每一个语句至少执行一次,并且使断定表达式中的每一个条件都取到各类可能的结果。

测试数据使a点有下述各类结果:

     A>1,A≤1,B=0,B≠0.

测试数据使b点有下述各类结果:

     A=2,A≠2, X>1, X≤1.

须要输入下面的测试数据:

    A=2,B=0,X=1    (路径是:sacbed)

    A=1,B=1,X=2    (路径是:sabed )    (少bd分支)

    条件覆盖一般比断定覆盖强,它使断定表达式中每一个条件都取到了两个不一样的结果;不必定包含断定覆盖.

    断定覆盖只关心整个断定表达式的值。

 

含义:不只每一个语句至少执行一次,并且使断定表达式中的每一个条件都取到各类可能的结果。

测试数据使a点有下述各类结果:

     A>1,A≤1,B=0,B≠0.

测试数据使b点有下述各类结果:

     A=2,A≠2, X>1, X≤1.

另外一组测试数据:

    A=2,B=0,X=4        (路径是:sacbed)

    A=1,B=1,X=1        (路径是:sabd )

  包含了断定覆盖。

 

4. 断定/条件覆盖

    断定覆盖不必定包含条件覆盖,条件覆盖也不必定包含断定覆盖。

由于:断定表达式中的每一个条件都取到各类可能的结果,但不能保证每一个断定表达式也都取到各类可能的结果。

提出了断定/条件覆盖。

断定/条件覆盖:一种能同时知足这两种覆盖标准的逻辑覆盖。

含义:选取足够多的测试数据,使得断定表达式中的每一个条件都取到各类可能的值,并且每一个断定表达式也都取到各类可能的结果。

有时断定/条件覆盖并不比条件覆盖更强。

 

测试数据使a点有下述各类结果:

     A>1,A≤1,B=0,B≠0.

测试数据使b点有下述各类结果:

     A=2,A≠2, X>1, X≤1.

测试数据:

    A=2,B=0,X=4        (路径是:sacbed)

    A=1,B=1,X=1        (路径是:sabd )

也符合条件覆盖。

有时断定/条件覆盖并不必定比条件覆盖更强。

 

5. 条件组合覆盖

含义:使得每一个断定表达式中条件的各类可能组合都至少出现一次。

共有8种组合:

     A>1,B=0 ,                       A>1,B≠0

     A≤1,  B=0,                       A≤1,  B≠0.

     A= 2,   X>1,                       A= 2 ,  X≤1

     A≠2,   X>1,                      A≠2,   X≤1

测试数据:

    A=2,B=0,X=4        (路径是:sacbed)

    A=2,B=1,X=1        (路径是:sabed )

    A=1,B=0,X=2        (路径是:sabed)

    A=1,B=1,X=1        (路径是:sabd )

 

    知足条件组合覆盖标准的测试数据,必定知足断定覆盖、条件覆盖和断定/条件覆盖标准。

   是更强的逻辑覆盖标准。

   但不必定能使程序中的每条路径都执行到。

     如:sacbd

 

6. 点覆盖

含义:选取足够多测试数据,使得程序执行路径至少通过流图的每一个结点一次。

    因为流图的每一个结点与一条或多条语句相对应,显然,点覆盖标准和语句覆盖标准是相同的。

 

7. 边覆盖

含义:选取足够多测试数据,使得程序执行路径至少通过流图中每条边一次。

    一般边覆盖和断定覆盖是一致的。

 

8. 路径覆盖

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

  图7.5程序有4条可执行通路:

       sacbed,sacbd,sabed,sabd.

  为作到路径覆盖,一般须要4组测试数据。

 

 

 

7.6.2  控制结构测试

 

1. 基本路径测试

•McCabe提出的一种白盒测试技术;

•能够保证程序中的每条语句至少执行一次;

•每一个条件在执行时都将分别取真、假两种值。

 

  使用该技术设计测试用例的步骤以下:

第一步,根据过程设计结果画出相应的流图。

流图

   

复合条件的流图

 

第二步,计算流图的环形复杂度。

    前流图的环形复杂度为4。

 

第三步,肯定线性独立路径的基本集合。

    每一条新的路径都包含一条新边。

    程序的环形复杂度决定了程序中独立路径的数量。

 

第四步,设计可强制执行基本集合中每条路径的测试用例。

    一旦执行完全部测试用例,就能够确保程序中全部语句都至少被执行了一次,并且每一个条件都分别取过true值和false值。

 

 

P156例:测试用PDL描述的求平均值过程。

•首先画出图7.6所示的流图。

PROCEDURE average;
/* 这个过程计算不超过100个在规定值域内的有效数字的平均值;同时计算有效数字的总和及个数。*/
     INTERFACE RETURNS average, total.input, total.valid;
     INTERFACE ACCEPTS value, minimum, maximum;
     TYPE value[1100] IS SCALAR ARRAY;
     TYPE average, total.input, total.valid;
           minimum,maximum, sum IS SCALAR;
     TYPE i IS INTEGER;

1:    i=1;
    total.input=total.valid=0;
    sum=0;
2: DO WHILE value[i] <> -999
3:         AND total.input<100
4: increment total.input by1;
5: IF value[i]>=minimum
6:         AND value[i]<=maximum
7:  THEN increment total.valid by 1;
         sum=sum+value[i];
8:    ENDIF
       increment i by 1;
9: ENDDO
10:   IF total.valid>0
11:   THEN average=sum/total.valid;
12:   ELSE average=-999;
13:   ENDIF
      END average

 

 

图7.6 求平均值过程的流图

 

对于图7.6流图:

•环形复杂度为6,

•共有6条独立路径,P157

•设计执行每条路径的测试用例。P158

    一般在设计测试用例时,识别出断定结点是颇有必要的。本例中结点二、三、五、6和10是断定结点。

 

 

7.7  黑盒测试技术

• 黑盒测试着重测试软件功能。

• 黑盒测试不能取代白盒测试,是与白盒测试互补的测试方法,用于发现白盒测试不易发现的错误。

• 黑盒测试发现的错误类型:

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

   ②界面错误;

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

   ④性能错误;

   ⑤初始化和终止错误。

 

白盒测试主要用于测试过程的早期,

黑盒测试主要用于测试过程的后期。

设计黑盒测试方案时,应该考虑下述问题:

(1) 怎样测试功能的有效性?

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

(3) 系统是否对特定的输入值特别敏感?

(4) 怎样划定数据类的边界?

(5) 系统可以承受什么样的数据率和数据量?

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

 

应用黑盒测试技术,设计测试用例的标准:

(1) 可以减小为达到合理测试所须要设计的测试用例的总数;

(2) 可以告诉咱们,是否存在某些类型的错误,而不是仅仅指出与特定测试相关的错误是否存在。

 

黑盒测试技术:

•等价划分

•边界值分析

 

7.7.1  等价划分

等价划分:把程序的输入域划分红若干个数据类,据此导出测试用例。

    一个理想的测试用例能独自发现一类错误。

    穷尽的黑盒测试是不现实的。

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

•等价类:是指某个输入域的子集合。在该子集合中,各个输入数据对于揭露程序中的错误都是等效的。

•从等价类中选取一个数据进行测试,便可表明整个等价类中全部数据的测试结果,从而减小了测试时间和代价。

• 使用等价划分法设计测试方案,首先须要划分输入数据的等价类。

 

等价类划分规则:

(1) 若是规定了输入值的范围,则可划分出一个有效的等价类(输入值在此范围内),两个无效的等价类(输入值小于最小值或大于最大值);

         100 < x < 999

(2) 若是规定了输入数据的个数,则可划分出一个有效的等价类和两个无效的等价类;

(3) 若是规定了输入数据的一组值,并且程序对不一样输入值作不一样处理,则每一个容许的输入值是一个有效的等价类,此外还有一个无效的等价类(任一个不容许的输入值);

     X∈{1,3,5,7}

(4) 若是规定了输入数据必须遵循的规则,则能够划分出一个有效的等价类(符合规则)和若干个无效的等价类(从各类不一样角度违反规则);

(5) 若是规定了输入数据为整型,则能够划分出正整数、零和负整数等3个有效类;

(6)若是输入条件是一个布尔量,则可定义一个有效等价类和一个无效等价类。

       X为布尔量

实际状况变幻无穷,根本没法一一列出。

 

划分出等价类之后,根据等价类设计测试方案时主要使用下面两个步骤:

(1) 设计一个新的测试方案以尽量多地覆盖还没有被覆盖的有效等价类,重复这一步骤直到全部有效等价类都被覆盖为止;

(2) 设计一个新的测试方案,使它覆盖一个并且只覆盖一个还没有被覆盖的无效等价类,重复这一步骤直到全部无效等价类都被覆盖为止。

    由于程序发现一类错误后就再也不检查是否还有其余错误,所以,每一个测试方案只覆盖一个无效的等价类。

 

 

下面用等价划分法设计一个简单程序的测试方案。

假设有一个把数字串转变成整数的函数。计算机字长16位,用二进制补码表示整数。这个函数是用Pascal语言编写的,它的说明以下:function strtoint (dstr:shortstr):integer;函数的参数类型是shortstr,它的说明是:type shortstr=array[1..6] of char;被处理的数字串是右对齐的,若是数字串比6个字符短,则在它的左边补空格。若是数字串是负的,则负号和最高位数字紧相邻(负号在最高位数字左边一位)。

 

能够划分出以下等价类:

 

• 有效输入的等价类有:

(1) 1~6个数字字符组成的数字串(最高位数字不是零);

(2) 最高位数字是零的数字串;

(3) 最高位数字左邻是负号的数字串;

 

• 无效输入的等价类有:

(4) 空字符串(全是空格);

(5) 左部填充的字符既不是零也不是空格;

(6) 最高位数字右面由数字和空格混合组成;

(7) 最高位数字右面由数字和其余字符混合组成;

(8) 负号与最高位数字之间有空格;

 

• 合法输出的等价类有:

(9) 在计算机能表示的最小负整数和零之间的负整数;

(10) 零;

(11) 在零和计算机能表示的最大正整数之间的正整数;

 

• 非法输出的等价类有

(12) 比计算机能表示的最小负整数还小的负整数;

(13) 比计算机能表示的最大正整数还大的正整数。

    由于所用计算机字长16位,能表示的最小负整数是-32 768,能表示的最大正整数是32 767。

 

7.7.2  边界值分析

    人们从长期的测试工做经验得知,大量的错误是发生在输入或输出范围的边界上,而不是在输入范围的内部。

• 针对各类边界状况设计测试用例,能够查出更多的错误

• 对等价类方法的补充

 

好比,在作三角形计算时,要输入三角形的三个边长:A、B和C。

这三个数值应当知足:

    A>0、B>0、C>0、

    A+B>C、A+C>B、B+C>A,

但若是把 “>”错写成 “≥”,那就不能构成三角形。问题恰出如今容易被疏忽的边界附近。

 

使用边界值分析方法设计测试方案:

•首先应该肯定边界状况。

•应该选取恰好等于、刚刚小于和刚刚大于边界值的数据做为测试数据,而不是选取每一个等价类内的典型值或任意值做为测试数据。

         100 < x < 999

    一般设计测试方案时老是联合使用等价划分和边界值分析两种技术。

 

7.7.3  错误推测

• 经验代表,在一段程序中已经发现的错误数目每每和还没有发现的错误数成正比。

    例如,在IBM OS/370操做系统中,用户发现的所有错误的47%只与该系统4%的模块有关。

    所以,要着重测试那些已发现了较多错误的程序段。

• 等价划分法和边界值分析法都只孤立地考虑各个输入数据的测试功效,而没有考虑多个输入数据的组合效应,可能会遗漏了输入数据易于出错的组合状况。

• 选择输入组合的一个有效途径是利用断定表或断定树为工具,列出输入数据各类组合与程序应做的动做(及相应的输出结果)之间的对应关系,而后为断定表的每一列至少设计一个测试用例。

 

7.8  调试

•调试也称排错。

•调试与测试的关系主要体如今如下几个方面:

  (1)测试的目的是暴露错误;而调试的目的是发现错误,改正错误。

  (2)测试是揭示设计人员的过失,一般应由非设计人员来承担;而调试是帮助设计人员纠正错误,能够由设计人员本身承担。

  (3)测试发现错误后,当即进行调试并改正错误,而后进行再测试(回归测试)。

  (4)调试用例与测试用例能够一致,也能够不一致。

7.8.1  调试过程

调试老是发生在测试以后,如图7.8所示。

    调试过程从执行一个测试用例开始,评估测试结果,若是发现实际结果与预期结果不一致,代表在软件中存在隐藏的问题。调试过程试图找出问题的缘由,以便改正错误。

调试过程总会有如下两种结果之一:

 ①找到了问题的缘由并把问题改正和排除掉了;

 ②没找出问题的缘由。此时,调试人员能够猜测一个缘由,并设计测试用例附加测试,重复此过程直至找到缘由并改正了错误。

 

图7.8 调试过程

7.8.2  调试途径

调试的目标:是寻找软件错误的缘由并改正错误。通常说来,有下列途径能够采用:

•试探法

•回溯法

•对分查找法

•概括法

•演绎法

 

1.试探法

  分析错误征兆,猜想发生错误的大概位置,而后利用有关的调试技术进一步得到错误信息。这种策略每每是缓慢而低效的。

 

2. 回溯法

•首先检查错误征兆,肯定最早发现错误的位置,而后人工沿程序的控制流往回追踪源程序代码,直到找出错误根源或肯定故障范围为止。

•回溯法对于小程序而言是一种比较好的调试策略。可是对于大程序,其回溯的路径数目会变得很大,以致使完全回溯成为不可能。

•回溯法的另外一种形式是正向追踪,即便用插入打印语句的方法检查一系列中间结果,以肯定最早出现错误的地方。

 

3.对分查找法

  在程序的中点附近输入某些变量的正确值(如利用赋值语句或输入语句),而后观察程序的输出。若输出结果正确,则说明错误出如今程序的前半部分;不然,说明程序的后半部分有错。对于程序中有错的那部分再重复使用这个方法,直到把错误范围缩小到容易诊断的程度为止。

 

4.概括法

概括法:是从个别推断全体,即从线索(错误征兆)出发,经过分析这些线索之间的关系而找出故障。这种方法主要有如下四个步骤:

①收集已有的使程序出错与不出错的全部数据。

②整理这些数据,以便发现规律或矛盾。

③提出关于故障的若干假设。

④证实假设的合理性,根据假设排除故障

 

5.演绎法

•演绎法是从通常原理或前提出发,通过删除和精化的过程,最后推导出结论。

•用演绎法排错时,首先要列出全部可能形成出错的缘由和假设,而后逐个排除,最后证实剩下的缘由确实是错误的根源。演绎法排错主要有如下四个步骤:

    ①设想全部可能产生错误的缘由。

    ②利用已有的数据排除不正确的假设。

    ③精化剩下的假设。

    ④证实假设的合理性,根据假设排除故障。

 

7.9  软件可靠性  

7.9.1  基本概念

1.  软件可靠性的定义

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

    随着运行时间的增长,运行时出现程序故障的几率也将增长,可靠性随着给定的时间间隔的加大而减小。

按照IEEE的规定

错误:是由开发人员形成的软件差错(bug)。

故障:是由错误引发的软件的不正确行为。

 

2. 软件的可用性

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

可靠性和可用性之间的主要差异是:

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

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

    所以,若是在时刻t系统是可用的,则有下述种种可能:

    在0到t这段时间内,系统一直没失效(可靠);

    在这段时间内失效了一次,可是又修复了;

    在这段时间内失效了两次修复了两次;……

 

7.10  小结

实现包括编码和测试两个阶段。

    编码是在对软件进行了整体设计和详细设计以后进行的,它只不过是把软件设计的结果翻译成用某种程序设计语言书写的程序,所以,程序的质量基本上取决于设计的质量。

    可是,编码使用的语言,特别是写程序的风格,也对程序质量有至关大的影响。

 

    软件测试仍然是保证软件可靠性的主要手段。

    测试阶段的根本任务是发现并改正软件中的错误。

    软件测试是软件开发过程当中最艰巨最繁重的任务,应该分阶段地进行,分为单元测试、集成测试和验收测试3个基本阶段。

    设计测试方案是测试阶段的关键技术问题,基本目标是选用最少许的高效测试数据,作到尽量完善的测试,从而尽量多地发现软件中的问题。

    两种测试途径:计算机进行测试,人工进行测试(例如,代码审查)。两种途径各有优缺点,互相补充,缺一不可。

 

    白盒测试和黑盒测试是软件测试的两类基本方法,这两类方法各有所长,相互补充。

    在测试过程的早期阶段主要使用白盒方法,而在测试过程的后期阶段主要使用黑盒方法。

    设计白盒测试方案的技术主要有,逻辑覆盖和控制结构测试;

    设计黑盒测试方案的技术主要有,等价划分、边界值分析和错误推测。

 

    在测试过程当中发现的软件错误必须及时改正,这就是调试的任务。

    为了改正错误,首先必须肯定错误的准确位置,如须要修正原来的设计,必须通盘考虑统筹兼顾,而不能“头疼医头、脚疼医脚”,应该尽可能避免在调试过程当中引进新错误。

    测试和调试是软件测试阶段中的两个关系很是密切的过程,它们每每交替进行。

 

 

 

相关文章
相关标签/搜索