第五章 结构化实现
o 编码
o 软件测试基础
o 白盒测试技术
o 黑盒测试技术
o 测试策略
o 调试
通常把编码和测试统称为实现 。
所谓编码就是选择一种语言把软件设计阶段
的 结果 翻译成计算机可以理解的源程序。
作为软件工程过程的一个阶段,编码是设计
的自然结果。因此,程序的质量主要取决于软件
设计的质量。
但是,所选用的程序设计语言的特点和编码
风格也会对程序的可靠性、可读性、可测试性和
可维护性产生深远影响。
第一节 编 码
一, 编码阶段的任务
主要任务:为每个模块编写程序,将详细设
计的结果转换成用某种程序语言表示的计算机能
理解的源程序形式。
在编程过程中,要把软件详细设计的表达翻
译成编程语言的构造。
二、程序设计语言的选择
1、程序设计特性:
心理特性
编程语言是人 ---机通信的工具,编码过程是
一种人的活动。因此,语言的心理特征对通信的
质量有重要的影响。
美国关于软件的心理学家指出:软件心理学
家的作用是在关注机器效率、软件能力和硬件限
制的同时,应把注意力集中在诸如使用容易、学
习简便、提高可靠性、减少出错率及让用户满意
方面。
虽然,有很多编程的自动化辅助工具,然而
软件工程仍然是高度的人工活动过程。因此,有
许多关于人的问题需要研究。特别是语言的心理
学特性对代码的翻译和实现的设计有相当重要的
影响。
一般考虑如下几个心理特性:
1)一致性
一致性是一个心理学而不是数学原则。即是
,一件事情应该以同一种方式完成。,
一种语言的限制越多,你就会越担心其他限
制,从而缩手缩脚。即使出现在语言的其它部分,
他们也会影响对当前无限制部分的使用。
一致性的另一个重要方面是,同一个语法结
构在不同的上下文不应该有不同的意思。
如括号的匹配使用。
2)多义性:是指程序员的多种理解的错误。
如,X=sinxlog(x+1),可理解为:
X=(sinx)(log(x+1))也可理解为
X=sin(xlog(x+1))
另一种引起多义性的原因是:允许不规范的
使用有缺省值的数据类型的标识符。如 FORTRAN
中标识符 KDELTA按缺省应认为有整数特征,然后,
REAL KDELTA一个显式说明,就赋于 KDELTA以浮
点特征。此处,由于心理上的多义性就可能产生
混惑。
3)紧凑性:一种面向代码信息量的表示,
这个信息量必须由人来记忆。
APL语言是一种非常紧凑的编程语言,
但很难读懂。逻辑语言也一种非常紧凑的
语言。度量紧凑性的语言属性有:
4)局部性:人的记忆有, 联觉, 和, 顺序,
两种。我们是凭借联觉记忆去识别人脸、邻居或
是书中某一页的版面布局,而不去追究其细节。
所谓的联觉记忆能力,是我们记忆力中的一部分,
它可以使我们在一瞬间,把事物作为一个整体来
记忆。所谓顺序记忆能力则更多地与听觉有关,
听过 9个音符后,就可以把第 10 个哼唱出来,但
要求直接唱出某个音符,就难多了。顺序记忆类
似于议程不定的链条。
局部性是编程语言的综合特性。当语句
可以组合为程序块、结构化构造可直接实
现、设计代码和合成代码具有高的模块性
的聚合时,局域性就高。
如语言特性支持或鼓励异常处理时,局
域性就低。
5)线性:是一种心理特征它与保持功能
域的概念紧密联系。当遇到一个逻辑运算
线性序列时,人就容易理解。外延分支和
外延大的循环都违反了处理的线性。结构
化构造的直接实现有助于编程语言的线性。
工程特性
易转换性
编译效率
可移植性
是否有开发工具
源程序的可维护性
2、语言的分类
? 基本语言 (Fortran,Basic,Algol,Cobol)
? 结构化程序语言 (Pascal,C)
? 专用语言
传统分法的可分为:
按“代”来分,可分为:
第一代语言,主要特征,面向机器,代表语
言是机器语言 (使用的是绝对地址码、绝对操作
码和存储空间分配 )、汇编语言 。
第二代语言, 50年代 ---60年代初,主要特征,
脱离机器面向算法过程的高级语言。有变量、赋
值、子程序、函数调用概念,有少量的基本数据
类型,有限的循环套和一般的递归调用等。代表
语言,FORTRAN,ALGOL,COBOL,BASIC(第三代语言
的基础 )
第三代语言,也称结构化编程语言,60年
代 —70年代,特点是:具有很强的过程和数据
结构化的能力。 可分为三类,通用高级语言
(C,Pascal,Ada美国的三军通用语言 )、面向
对象高级语言 (C++,Objective-C,Smalltalk,
Eiffel)、专用语言 (LISP,PROLOG,APL和
FORTH)
第四代语言, 70年代后,主要特征是用户极
端友好、声明式、交互式和非过程式的编程语言、
高效的程序代码、智能缺省假设、完备的数据库、
应用程序生成器。代表语言,FOXPRO,VFP,VC、
VB等等。
4GL溶入了许多新发展的技术,如,事件驱动、
分布式数据共享、多媒体技术,4GL是一个交互
式的程序设计环境。
3、程序设计语言的选择
一般来说来,高级语言明显优于汇编语言,
因此,除了在很特殊的应用领域 (例如,对程序
执行时间和使用的空间都有很严格限制的情况;
体系结构特殊的微处理机,以致在这类机器上通
常不能实现高级语言编译程序 ),或者大型系统
中执行时间非常关键的 (或直接依赖于硬件的 )一
小部分代码需要用汇编语言书写之外,其他程序
宜用高级语言书写。
为了降低软件开发和维护的总成本, 提高软
件的可靠性, 选择程序设计语言的理想标准是:
( 1) 选用的高级语言应该有理想的模块化机
制, 以及可读性好的控制结构和数据结构;
( 2) 选用的语言应该使编译程序能够尽可能
多地发现程序中的错误;
( 3) 选用的语言应该具有良好的独立编译机
制 。
但是在实际选用语言时不能仅仅考虑理论上
的标准,还必须同时考虑实用方面的各种限制。
二,编码风格
良好的源程序代码应该是的逻辑简明清晰、易
读易懂,为了做到这一点,应该遵循下述规则:
1,
所谓程序内部的文档包括:
?恰当的 标识符
?适当的 注解语句
?程序的 组织视觉
1、标识符指变量的命名。
2、注释语句分为两类:
序言性注释语句
描述性注释语句
3、组织视觉是指写程序的形式布局。如,
缩格风格。
2.
虽然在设计期间已经确定了数据结构的组织
和复杂程度,然而数据说明的风格却是在写程序
时确定的。
为了使数据更容易理解和维护,遵循一些比
较简单的原则是必要的。
3.
基本原则:简明扼要
每个语句都应该简单而直接,不能为了提高效率而使
程序变得过分复杂。
一行只写一条语句。
4 输入 /
? 对所有输入数据都进行检验;
? 检查输入项重要组合的合法性;
? 保持输入格式简单;
? 使用数据结束标记,不要要求用户指定数据
的数目;
? 明确提示交互式输入的请求,详细说明可用
的选择或边界数值;
? 当程序设计语言对格式有严格要求时,应保
持输入格式一致;
? 设计良好的输出报表;
? 给所有输出数据加标志。
5,效率
效率主要指 处理机时间 和 存储器容量 两个方
面 。 虽然值得提出提高效率的要求, 但是在进一
步讨论这个问题之前应该记住三条原则,首先,
效率是性能要求, 因此应该在需求分析阶段确定
效率方面的要求 。 其次, 效率是靠好设计来提高
的 。 第三, 程序的效率和程序的简单程度是一致
的 。 不要牺牲程序的清晰性和可读性来不必要地
提高效率 。
第二节 软件测试基础
无论怎样强调软件测试的重要性和它对软件
可靠性的影响都不过分。在开发大型软件系统的
漫长过程中,面对着极其错综复杂的问题,人的
主观认识不可能完全符合客观现实,与工程密切
相关的各类人员之间的通信和配合也不可能完美
无缺,因此,在软件生命周期的每个阶段都不可
避免地会产生差错。
我们力争在每个阶段结束之前进行严格的技
术审查,尽可能及早发现并纠正差错。但是,经
验表明审查并不能发现所有差错,此外在编码过
程中还不可避免地会引入新的错误。如果在软件
投入生产性运行之前,没有发现并纠正软件中的
大部分差错,则这些差错迟早会在生产过程中暴
露出来,那时不仅改正这些错误的代价更高,而
且往往会造成很恶劣的后果。
测试的目的就是在软件投入生产性运行之前,
尽可能多地发现软件中的错误。
目前软件测试仍然是保证软件质量的关键步
骤,它是对软件规格说明、设计和编码的最后复
审。
大量统计资料表明,软件测试的工作量往往
占软件开发总工作量的 70%以上。极端情况下,
测试那种关系人的生命安全的软件所花费的成本,
可能相当于软件工程其他步骤总成本的 3~ 5倍。
因此,必须高度重视软件测试工作,绝不要以为
写出程序之后软件开发工作就接近完成了,实际
上,大约还有同样多的开发工作量需要完成。
测试目的 是发现软件中的错误,但是,发现
错误并不是软件开发的最终目的。软件工程的根
本目标是开发出高质量的完全符合用户需要的软
件。因此,通过测试发现错误之后还必须诊断并
改正错误,这就是调试,调试是测试阶段最困难
的工作。在对测试结果进行收集和评价的时候,
软件所达到的可靠性也开始明朗了。软件可靠性
模型使用故障率数据,估计软件将未来出现故障
的情况并预测软件的可靠性。
一, 测试目标
G,Myers给出了关于测试的一些规则, 这些
规则也可以看作是测试的目标或定义:
测试是为了发现程序中的错误而执行程序的
过程;好的测试方案是极可能发现迄今为止尚未
发现的错误的测试方案;成功的测试是发现了至
今为止尚未发现的错误的测试。
由于测试的目标是暴露程序中的错误,从心
理学角度看,由程序的编写者自己进行测试是不
恰当的。因此,在综合测试阶段通常由其他人员
组成测试小组来完成测试工作。
测试的目的在于寻找错误,并且找出的错误
越多越好。那么,能不能把所有隐藏的错误全都
找出来呢?或者说能不能把所有可能做的测试无
遗漏地一一做完呢?这是不可能的。测试只能进
行有限次,一次测试只是一次抽样。所以,在不
论多少次测试中,如果都没有发现错误,也不能
证明软件没有错误。
x
y
z
(X,y,z是 16位二进制数 )
每个数有 216种,三个数的组合数有
216× 216× 216 ≈248 ≈3× 1014种,假定每次执行一次程序
需要一毫秒,执行 3× 1014次大约需要一万年 ! 才能测试完
毕。不可能进行穷尽测试。只能进行有限次的抽样测试。
一个好的测试,既要尽可能发现更多的错误,
又要经济,即要提高测试效率。要做到这点,关
键在于设计测试用例,必须精心设计测试用例,
挑选尽可能少的测试数据,使得采用这些测试数
据能够达到最佳的效果,或说能够高效率地把隐
藏的错误揭露出来。
二, 测试对象
软件测试并不等于程序测试。软件测试应贯
穿于软件定义与开发的整个期间。因此,需求分
析、概要设计、详细设计以及程序编码等各阶段
所得到的文档,包括需求分析规格说明书、概要
设计规格说明、详细设计规格说明以及源程序,
都应成为软件测试的对象。软件测试不仅限在程
序测试的狭小范围内,而应考虑到其他阶段的所
有工作。
需求分析
程序编码
详细设计
概要设计
需求规格说明书
概要设计规格说明
源程序代码
详细设计规格说明
测试对象
三, 黑盒测试和白盒测试
黑盒测试和白盒测试是设计测试用例的两种
方法。
黑盒测试法 把程序看成一个黑盒子,完全不
考虑程序的内部结构和处理过程。
黑盒测试是在程序接口进行的测试。
它只检查程序功能是否能按照规格说明书的
规定正常使用,程序是否能适当地接收输入数据
产生正确的输出信息,并且保持外部信息 (如,
数据库或文件 )的完整性,完全不考虑程序内部
的逻辑结构和内部特征。
输入 输入
黑盒测试主要是为了发现以下六类错误:
1,是否有不正确或遗漏了的功能?
2,在接口上,输入能否正确地接受?能否
输出正确的结果?
3,性能上是否能够满足要求?
4,是否有初始化或终止性错误?
5,界面错误?
6,数据结构错误或外部数据库访问错误?
白盒测试法 的前提是可以把程序看成装在一
个透明的白盒子里,也就是完全了解程序的结构
和处理过程。
白盒测试又称为结构测试或称为逻辑驱动测
试。
这种方法按照程序内部的逻辑测试程序,检
验程序中的每条通路是否都能按预定要求正确
工作。
测试内部程序
白盒测试主要对程序进行如下检查:
1,对程序模块的所有独立的执行路径至少
测试一次;
2,对所有的逻辑判定,取, 真,,与取
,假, 的两种情况都能到少测试一次;
3,在循环的边界和运行界限内体;
4,测试内部数据结构的有效性。
四, 测试准则
为了能设计出有效的测试方案,软件人员必
须充分理解并正确运用指导软件测试的基本准则,
主要的测试准则如下:
( 1)及早地和不断地进行软件测试;
( 2)测试前要认定被测软件有错,充分注意
测试中的集群现象;
( 3)所有的测试都应该以软件需求规格说明
书为准需求;
( 4) 设计测试用例时, 应当兼顾合理输入与
不合理输入数据;
( 5) 穷举测试是不可能的 。
( 6) 为了达到最佳的测试效果, 应该由独立
的第三方来从事测试工作 。
测试准则:
五, 测试信息流
测试信息流如图所示, 测试有二类输入:
测试
排错
可靠性
分析
结果
分析
测
试
配
置
测
试
工
具
测
试
结
果
预
期
结
果
出 错
出
错
概
率
数
据
改正的软件
预测的可靠性
测试信息流
第三节 白盒测试
通常又把测试数据和预期的输出结果称为 测
试用例 。
白盒测试的设计测试用例方法有:
逻辑覆盖、基本路径测试、条件测试、数据
流测试、循环测试等五种技术。
所谓 测试方案 包括具体的测试目的 (例如,要
测试的具体功能 ),应该输入的测试数据和预期
的输出结果。
不同的测试数据发现程序错误的能力差别很
大,为了提高测试效率降低测试成本,应该选用
高效的测试数据。
因为不可能进行穷尽的测试,选用少量, 最
有效的, 测试数据,做到尽可能完备的测试就更
重要了。
一、逻辑覆盖
所谓逻辑覆盖是一系列对程序内部逻辑测试
过程的总称。主要有:
语句覆盖、判定覆盖、条件覆盖、
判定 /条件覆盖、组合条件覆盖等。
下面以例说明。
例如,,它的源程序如下:
procedure example (A,B,real ; var X:
real) ;
begin
if (A>1) and (B=0)
then X,= X/A;
if(A=2) or (X>1)
then X,= X+1
end;
被测试模块的流程图
入 口
A = 2
o r X > 1
X = X / A
X = X + 1
返 回
A > 1
a n d B = 0
T
F
F
T
1
7
6
5
4
3
2
S
a
b
d
c
e
为了暴露程序中的错误, 至少每个语句应该
执行一次 。 语句覆盖的含义是选择足够多的测试
数据, 使被测程序中每个语句至少执行一次 。
测试用例的设计格式,( A,B,x)
上例的语句覆盖的测试用例是,( 2,0,4) 。
1,语句覆盖
入口
A= 2
or X>1
X= X/A
X=X+1
返回
A> 1
and B= 0
T
F
F
T
1
7
6
5
4
3
2
S
a
b
d
c
e
2.
判定覆盖又叫分支覆盖, 它的含义是, 不
仅每个语句必须至少执行一次, 而且每个判定的
每种可能的结果都应该至少执行一次, 也就是每
个判定的每个分支都至少执行一次 。
上例的判定覆盖的测试用例是:
( 2,0,4)和( 0,1,4)。
3
条件覆盖的含义是, 不仅每个语句至少执
行一次, 而且使判定表达式中的每个条件都取到
各种可能的结果 。
上例的条件覆盖的测试用例是:
( 2,0,4) 和 ( 1,1,1) 。
既然判定覆盖不一定包含条件覆盖,
条件覆盖也不一定包含判定覆盖, 自然会提出一
种能同时满足这两种覆盖标准的逻辑覆盖, 这就
是判定 /条件覆盖 。 它的含义是, 选取足够多的
测试数据, 使得判定表达式中的每个条件都取到
各种可能的值, 而且每个判定表达式也都取到各
种可能的结果 。
上例的判定 /条件覆盖的测试用例是:
( 2,0,4) 和 ( 1,1,1) 。
4.判定 /条件覆盖
5.
条件组合覆盖是更强的逻辑覆盖标准, 它
要求选取足够多的测试数据, 使得每个判定表达
式中条件的各种可能组合都至少出现一次 。 上例
的条件组合是:
( 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
上例的条件组合覆盖的测试用例是:
( 2,0,4)
( 1,1,1)
( 2,1,1)
( 1,0,2)
二, 基本路径测试
基本路径测试是 Tom McCabe提出的一种白盒
测试技术。使用这种技术设计测试用例步骤:
1、计算详细设计结果的逻辑复杂度;
2、定义独立执行路径的基本集合;
3、从该基本集合导出的测试用例可以保证程
序中的每条语句至少执行一次,而且每个条件在
执行时都将分别取 true(真 )和 false(假 )值。
1,根据过程设计结果画出相应的流图
PROCEDURE average; /*这个过程计算不超过 100个在
规定值域内的有效数字的平均值;同时计算有效数字的总
和及个数 。 */
INTERFACE RETURNS average,total input,total
valid;
INTERFACE ACCEPTS value,minimum,maximum;
TYPE value? 1...100? 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,IFtotal valid> 0
11,THEN average= sum/total valid;
12,ELSEaverage= -999
13,ENDIF
END average
1
12 11
10
9
78
6
5
4
2
3
13
求平均值过程的流图
2,计算流图的环形复杂度
环形复杂度定量度量程序的逻辑复杂性。有
了描绘程序控制流的流图之后,可以用下述三种
方法之一来计算环形复杂度。
( 1) 流图中的区域数 (包括有界和无界 )等于环
形复杂度 。
( 2) 流图 G的环形复杂度 V(G)= E-N+2p,其中 E是
流图中边的条数, N是流图中节点数,p是联结成分的
个数 。
( 3) 流图 G的环形复杂度 V(G)= Q+1,
其中 Q是流图中判定节点的数目 。
使用上述任何一种方法,都可以计算出上例所示
流图的环形复杂度为 6。
3,确定线性独立路径的基本集合
所谓独立路径是指至少引入程序的一个新处
理语句集合或一个新条件的路径 。 用流图术语描
述, 独立路径至少包含一条在定义该路径之前不
曾用过的边 。
使用基本路径测试法设计测试用例时,程序
的环形复杂度决定了程序中独立路径的数量,而
且这个数是确保程序中所有语句至少被执行一次
所需的测试数量的上界。
对于上图所描述的求平均值过程来说, 由于
环形复杂度为 6,因此共有 6条独立路径 。 例如,
下面列出了 6条独立路径:
路径 1,1-2-10-11-13
路径 2,1-2-10-12-13
路径 3,1-2-3-10-11-13
路径 4,1-2-3-4-5-8-9-2- …
路径 5,1-2-3-4-5-6-8-9-2- …
路径 6,1-2-3-4-5-6-7-8-9-2- …
路径 4,5,6后面的省略号 (...)表示, 可以
后接通过控制结构其余部分的任意路径 (例如,
10-11-13)。
通常在导出测试用例时,识别出判定节点是
很有必要的。本例中节点 2,3,5,6和 10是判定
节点。
4.设计可强制执行基本集合中每条路径的测
应该选取数据使得在测试每条路径时都适当
地设臵好了各个判定节点的条件 。 可以测试上述
路径 1
value? k? =有效输入值, 其中 k< i(i的定
义在下面 )
value? i? = -999,其中 2≤i≤ 100
预期结果:基于 k的正确平均值和总数
注意, 路径 1无法独立测试, 必须作为路径 4、
5和 6的一部分来测试 。
路径 2
value? 1? = -999
预期结果,average= -999,其他都保持初始
值 。
路径 5
value? i? =有效输入值, 其中 i< 100
value? k? > maximum,其中 k< i
预期结果:其于 k的正确平均值和总数
路径 6
value? i? =有效输入值, 其中 i< 100
预期结果:正确的平均值和总数
三, 条件测试
尽管基本路径测试技术简单而且高效, 但是
仅有这种技术还不够, 还需要使用其他控制结构
测试技术, 才能进一步提高白盒测试的质量 。
用条件测试技术设计出的测试用例,能够检
查程序模块中包含的逻辑条件。一个简单条件是
一个布尔变量或一个关系表达式,在布尔变量或
关系表达式之前还可能有一个 NOT(,┐,)算符。
E1<关系算符> E2
其中, E1和 E2是算术表达式, 而<关系算符>
是下列算符之一:, <,,, ≤,,, =,,
,≠,,, >, 或, ≥, 。 复合条件由两个或多
个简单条件, 布尔算符和括弧组成 。 布尔算符有
OR(“|, ),AND(“&”)和 NOT(,┐,)。 不包含关
系表达式的条件称为布尔表达式 。
在上述种种条件测试技术的基础上,K.C.Tai
提出了一种被称为 BRO(Branch and Relational
Operalor)测试的条件测试策略。
如果在条件中所有布尔变量和关系算符都只
出现一次而且没有公共变量,则 BRO测试保证能
发现该条件中的分支错和关系算符错。
BRO测试利用条件 C的条件约束来设计测试用
例 。 包含 n个简单条件的条件 C的条件约束定义为
(D1,D2,…, Dn),其中 D i(0< i≤n) 表示条件
C中第 i个简单条件的输出约束 。 如果在条件 C的
一次执行过程中, C中每个简单条件的输出都满
足 D中对应的约束, 则称 C的这次执行覆盖了 C的
条件约束 D。
对于布尔变量 B来说, B的输出约束指出, B必
须是真 (t)或假 (f)。 类似地, 对于关系表达式来
说, 用符号>, =和<指定表达式的输出约束 。
作为一个例子,
C1,B1& B2
其中,B1和 B2是布尔变量。 C1的条件约束形式
为 (D1,D2),其中 D1和 D2中的每一个都是, t”或
,f”。值 (t,f)是 C1的一个条件约束,并由使 B1
值为真 B2值为假的测试所覆盖。 BRO测试策略要求,
约束集{ (t,t),(f,t),(t,f)}被 C1的执行
所覆盖。如果 C1因布尔算符错误而不正确,则至
少上述约束集中的一个约束将迫使 C1失败。
四, 数据流测试
数据流测试方法根据程序中变量定义和使用
的位臵, 选择程序的测试路径 。 为了说明数据流
测试方法, 假设已赋予程序每条语句一个唯一的
语句号, 而且每个函数都不修改它的参数或全局
变量 。 对于语句号为 S的语句
DEF(S)={ X|语句 S包含变量 X的定义 }
USE(S)={ X|语句 S使用变量 X}
如果 S是 if或循环语句,则它的 DEF集为空,
而它的 USE集取决于 S的条件。如果存在从语句 S
到语句 S′ 的路径,而且在该路径中不包含 X的任
何其他定义,则称变量 X在语句 S中的定义在语句
S′ 仍然有效。
变量 X的定义 ——使用链 (或称为 DU链 )的形
式为 ? X,S,S′ ?, 其中 S和 S′ 是语句号, X在
集合 DEF(S)和 USE(S′ )中, 而且在语句 S中对 X的
定义在语句 S′ 仍然有效 。
一种简单的数据流测试策略要求, 每个 DU链
至少被覆盖一次, 这种策略称为 DU测试策略 。
五, 循环测试
循环测试是一种白盒测试技术,它专注于测
试循环结构的有效性。在结构化的程序中通常只
有三种循环,分别是 简单循环, 串接循环 和 嵌套
循环。
1.
应该使用下列测试集来测试简单循环, 其中 n
是允许通过循环的最大次数 。
通过循环 m次, 其中 m< n-1
通过循环 n-1,n,n+1次。
简单循环 嵌套循环 串接循环
三种循环
2.
如果把简单循环的测试方法直接应用到嵌套
循环, 可能的测试数就会随嵌套层数的增加按几
何级数增长, 这会导致不切实际的测试数目 。
B.Beizer提出了一种能减少测试数的方法 。
( 1) 从最内层循环开始测试, 把所有其他循环
都设臵为最小值;
( 2) 对最内层循环使用简单循环测试方法, 而
使外层循环的迭代参数 (例如, 循环计数器 )取
最小值, 并为越界值或非法值增加一些额外的
( 3) 由内向外, 对下一个循环进行测试, 但保
持所有其他外层循环为 最小值, 其他嵌套循
环为, 典型,
( 4) 继续进行下去, 直到测试完所有循 。
3,串接循环
如果串接循环的各个循环都彼此独立, 则可
以使用前述的测试简单循环的方法来测试串接循
环 。 但是, 如果两个循环串接, 而且第一个循环
的循环计数器值是第二个循环的初始值, 则这两
个循环并不是独立的 。 当循环不独立时, 建议使
用测试嵌套循环的方法来测试串接循环 。
第四节 黑盒测试技术
黑盒测试着重测试软件的功能需求,也就是
说,黑盒测试让软件工程师设计出能充分检查程
序所有功能需求的输入条件集。黑盒测试并不能
取代白盒测试技术,它是与白盒测试互补的方法,
它很可能发现白盒测试不易发现的其他不同类型
的错误。
白盒测试在测试过程的早期阶段进行,而黑
盒测试主要用于测试过程的后期。黑盒测试故意
不考虑程序的控制结构,而把注意力集中于信息
域。
黑盒测试技术主要有:
等价分类法,边界值分析法、错误推断法
一,
等价分类法是一种黑盒测试方法,这种方法
把程序的输入域划分成若干个等价数据类,据此
可以导出测试用例。
如果把所有可能的输入数据 (有效的和无效的 )
划分成若干个等价类,则可以合理地做出下述假
定:
每类中的一个典型值在测试中的作用与这一
类中所有其他值的作用相同。
因此,可以从每个等价类中只取一组数据作
为测试数据。这样选取的测试数据最有代表性,
最可能发现程序中的错误。
使用等价划分法设计测试方案,首先需要划
分输入数据的等价类,为此需要研究程序的功能
说明,从而确定输入数据的有效等价类和无效等
价类。
在确定输入数据的等价类时常常还需要分析
输出数据的等价类,以便根据输出数据的等价类
导出对应的输入数据等价类。
划分等价类需要经验, 下述几条启发式规则
可能有助于等价类的划分 。
1,如果规定了输入值的范围, 则可划分出一
个有效的等价类 (输入值在此范围内 ),两个无效
的等价类 (输入值小于最小值或大于最大值 )。
2、如果规定了输入数据的个数,则类似地也
可以划分出一个有效的等价类和两个无效的等价
类。
3,如果规定了输入数据的一组值, 而且程序
对不同输入值做不同处理, 则每个允许的输入值
是一个有效的等价类, 此外还有一个无效的等价
类 (任一个不允许的输入值 )。
4、如果规定了输入数据必须遵循的规则,则
可以划分出一个有效的等价类 (符合规则 )和若干
个无效的等价类 (从各种不同角度违反规则 )。
5,如果规定了输入数据为整型, 则可以划分
出正整数, 零和负整数等三个有效类 。
6,如果程序的处理对象是表格, 则应该使用
空表, 以及含一项或多项的表 。
划分出等价类以后, 等价类设计测试方案时
主要使用下面两个步骤 。
1)设计一个新的测试方案以尽可能多地覆盖
尚未被覆盖的有效等价类,复重这一步骤直到所
2)设计一个新的测试方案,使它覆盖一个而
且只覆盖一个尚未被覆盖的无效等价类,重复这
一步骤直到所有无效等价类都被覆盖为止。
二, 边界值分析
经验表明,处理边界情况时程序最容易发生
错误。例如,许多程序错误出现在下标、纯量、
数据结构和循环等的边界附近。因此,设计使程
序运行在边界情况附近的测试方案,暴露出程序
错误的可能性更大一些。
使用边界值分析方法设计测试方案首先应该
确定边界情况,这需要经验和创造性,通常输入
等价类和输出等价类的边界,就是应该着重测试
的程序边界情况。选取的测试数据应该刚好等于、
刚刚小于和刚刚大于边界值。也就是说,按照边
界值分析法,应该选取刚好等于、稍小于和稍大
于等价类边界值的数据作为测试数据,而不是选
取每个等价类内的典型值或任意值作为测试数据。
三, 错误推测
错误推测法在很大程度上靠直觉和经验进行。
它的基本想法是列举出程序中可能有的错误和容
易发生错误的特殊情况,并且根据它们选择测试
方案。
第五节 测试策略
一、测试种类
单元测试 。 单元测试大量使用白盒测试技术,
检查模块控制结构中的特定路径, 以确保做到完
全覆盖并发现最大数量的错误 。
集成测试。 在装配的同时进行测试,集成测
试同时解决程序验证和程序构造这两个问题。在
集成过程中最常用的是黑盒测试用例设计技术,
当然,为了保证覆盖主要的控制路径,也可能使
用一定数量的白盒测试。
高级测试 。在软件集成完成之后,还需要进
行一系列高级测试。
确认测试 。必须测试在需求分析阶段确定下
来的确认标准,确认测试是对软件满足所有功能
的、行为的和性能的需求的最终保证。在确认测
试过程中仅使用黑盒测试技术。
二, 单元测试
通常,单元测试和编码属于软件工程过程的
同一个阶段。在编写出源程序代码并通过了编译
程序的语法检查之后,可以应用人工测试和计算
机测试这样两种类型的测试,完成单元测试工作。
这两种类型的测试各有所长,互相补充。人工测
试和计算机测试。
三, 集成测试
集成测试是测试和组装软件的系统化技术,
在把模块按照设计要求组装起来的同时进行测试,
主要目标是发现与接口有关的问题。
模块组装
成程序的
两种方法
渐增式测试
非渐增式测试
自低向上
自顶向下
自低向上
自顶向下
1.
自顶向下的集成 (结合 )方法是一个日益为人
们广泛采用的组装软件的途径。从主控制模块
(主程序 )开始,沿着软件的控制层次向下移动,
从而逐渐把各个模块结合起来。在把附属于 (以
及最终附属于 )主控制模块的那些模块组装到软
件结构中去时,或者使用深度优先的策略,或者
使用宽度优先的策略。
把模块结合进软件结构的具体过程由下述四
1) 对主控制模块进行测试, 测试时用 存根程
序
2)根据选定的结合策略 (深度优先或宽度优
先 ),每次用一个实际模块代换一个存根程序 (新
结合进来的模块往往又需要新的 存根程序 )
3)在结合进一个模块的同时进行测试;
4) 为了保证加入模块没有引进新的错误, 可
能需要进行回归测试 (即, 全部或部分地重复以
前做过的测试 )。
从第二步开始不断地重复进行上述过程,直
到构造起完整的软件结构为止。
2.
自底向上测试从, 原子, 模块 (即在软件结构
最低层的模块 )开始组装和测试。因为是从底部
向上结合模块,总能得到需要的下层模块处理功
能,所以不需要存根程序。
用下述步骤可以实现自底向上的结合策略:
1)把低层模块组合成实现某个特定的软件子
功能的模块群 ( 族 )
2) 开发一个 驱动模块 (用于测试的控制程序 ),
协调测试数据的输入和输出;
3)对每个模块群 ( 族 ) 进行测试;
4)去掉测试使用的 驱动程序, 用较高层模块
把模块群 ( 族 ) 组合成为完成更大功能的新模块
群 ( 族 ) 。
从第一步开始循环执行上面各步骤,直至整
个程序构造完成。
3,回归测试
每当一个新模块作为集成测试的一部分加进
来的时候,软件就发生了变化:建立了新的数据
流路径,可能出现了新的 I/O操作,激活了新的
控制逻辑。这些变化可能使原来工作正常的功能
出现问题。在集成测试的范畴中,所谓 回归测试
是指重新执行已经做过的测试的某个子集,以保
证上述这些变化没有带来非预期的副作用。
4,不同集成测试策略的比较
自顶向下 测试方法的主要 优点 是不需要测试
驱动程序,能够在测试阶段的早期实现并验证系
统的主要功能,而且能在早期发现上层模块的接
口错误。
自顶向下 测试方法的主要 缺点 是需要存根程
序,可能遇到与此相联系的测试困难,低层关键
模块中的错误发现较晚,而且用这种方法在早期
不能充分展开人力。
可以看出,自底向上测试方法的优缺点与上
述自顶向下测试方法的优缺点刚好相反。
四,
为了把握各个环节的正确性,需要进行各种
确认 和 验证 工作。确认测试也称为验收测试,它
的目标是验证软件的有效性。
用 户 要 求
用 户 要 我 做 什
么
运 行 结 果
计 算 机 程 序 运
行 结 果
需 求 说 明 书
分 析 员 可 以 提
供 什 么?
源 程 序
程 序 员 要 让 计
算 机 做 什 么?
设 计 说 明 书
设 计 员 要 让 计
算 机 做 什 么?
相 符 吗?
理 解 正 确 性
表 达 正 确 性
运 行 正 确 性
输 入 正 确 性
理 解 正 确 性
编 码 正 确 性
理 解 正 确 性
设 计 正 确 性
表 达 正 确 性
①
②
③
④
⑤
软件生存期各个阶段之间需要保持的正确性
验证指的是保证软件正确地实现了某一特定
要求的一系列活动,验证是试图证明在软件生存
期各个阶段以及阶段间的逻辑协调性、完备性和
正确性。
确认指的是保证软件的实现满足了用户需求
的一系列活动。其 目的 是证实在一个给定的外部
环境中软件的逻辑正确性。它包括 需求规格说明
的确认 和 程序的确认,而程序的确认又分为静态
确认与动态确认。 静态确认 一般不在计算机上实
际执行程序,而是通过人工分析或程序正确性证
明来确认程序的正确性; 动态确认 主要通过动态
分析和程序测试来检查程序的执行状态,以确认
程序是否有问题。
确认与验证工作都属于软件测试。在对需求
理解与表达的正确性、设计与表达的正确性、实
现与表达的正确性的验证中,任何一个环节上发
生了问题都有可能在软件测试中表现出来。
第六节 调试
调试 (也称为纠错 )作为成功的测试的后果而
出现, 也就是说, 调试是在测试发现错误之后排
除错误的过程 。
一, 调试过程
调试不是测试,但是它总是发生在测试之后。
如图 5-10所示,调试过程从执行一个测试用例开
始,评估测试结果,如果发现实际结果与预期结
果不一致,则这种不一致就是一个症状,它表明
在软件中存在着隐藏的问题。调试过程试图找出
产生症状的原因,以便改正错误。
二, 调试途径
无论采用什么方法,调试的根本目标都是寻
找软件错误的原因并改正之。这个目标是通过把
系统地评估、直觉和运气组合起来实现的。一般
?蛮干法;
?回溯法;
?原因排除法
三, 可靠性的基本概念
1.
软件可靠性是指程序在给定的时间间隔内,
按照规格说明书的规定, 成功地运行的概率 。
2,软件的可用性
软件可用性是指程序在给定的时间点,按照
规格说明书的规定,成功地运行的概率。
o 编码
o 软件测试基础
o 白盒测试技术
o 黑盒测试技术
o 测试策略
o 调试
通常把编码和测试统称为实现 。
所谓编码就是选择一种语言把软件设计阶段
的 结果 翻译成计算机可以理解的源程序。
作为软件工程过程的一个阶段,编码是设计
的自然结果。因此,程序的质量主要取决于软件
设计的质量。
但是,所选用的程序设计语言的特点和编码
风格也会对程序的可靠性、可读性、可测试性和
可维护性产生深远影响。
第一节 编 码
一, 编码阶段的任务
主要任务:为每个模块编写程序,将详细设
计的结果转换成用某种程序语言表示的计算机能
理解的源程序形式。
在编程过程中,要把软件详细设计的表达翻
译成编程语言的构造。
二、程序设计语言的选择
1、程序设计特性:
心理特性
编程语言是人 ---机通信的工具,编码过程是
一种人的活动。因此,语言的心理特征对通信的
质量有重要的影响。
美国关于软件的心理学家指出:软件心理学
家的作用是在关注机器效率、软件能力和硬件限
制的同时,应把注意力集中在诸如使用容易、学
习简便、提高可靠性、减少出错率及让用户满意
方面。
虽然,有很多编程的自动化辅助工具,然而
软件工程仍然是高度的人工活动过程。因此,有
许多关于人的问题需要研究。特别是语言的心理
学特性对代码的翻译和实现的设计有相当重要的
影响。
一般考虑如下几个心理特性:
1)一致性
一致性是一个心理学而不是数学原则。即是
,一件事情应该以同一种方式完成。,
一种语言的限制越多,你就会越担心其他限
制,从而缩手缩脚。即使出现在语言的其它部分,
他们也会影响对当前无限制部分的使用。
一致性的另一个重要方面是,同一个语法结
构在不同的上下文不应该有不同的意思。
如括号的匹配使用。
2)多义性:是指程序员的多种理解的错误。
如,X=sinxlog(x+1),可理解为:
X=(sinx)(log(x+1))也可理解为
X=sin(xlog(x+1))
另一种引起多义性的原因是:允许不规范的
使用有缺省值的数据类型的标识符。如 FORTRAN
中标识符 KDELTA按缺省应认为有整数特征,然后,
REAL KDELTA一个显式说明,就赋于 KDELTA以浮
点特征。此处,由于心理上的多义性就可能产生
混惑。
3)紧凑性:一种面向代码信息量的表示,
这个信息量必须由人来记忆。
APL语言是一种非常紧凑的编程语言,
但很难读懂。逻辑语言也一种非常紧凑的
语言。度量紧凑性的语言属性有:
4)局部性:人的记忆有, 联觉, 和, 顺序,
两种。我们是凭借联觉记忆去识别人脸、邻居或
是书中某一页的版面布局,而不去追究其细节。
所谓的联觉记忆能力,是我们记忆力中的一部分,
它可以使我们在一瞬间,把事物作为一个整体来
记忆。所谓顺序记忆能力则更多地与听觉有关,
听过 9个音符后,就可以把第 10 个哼唱出来,但
要求直接唱出某个音符,就难多了。顺序记忆类
似于议程不定的链条。
局部性是编程语言的综合特性。当语句
可以组合为程序块、结构化构造可直接实
现、设计代码和合成代码具有高的模块性
的聚合时,局域性就高。
如语言特性支持或鼓励异常处理时,局
域性就低。
5)线性:是一种心理特征它与保持功能
域的概念紧密联系。当遇到一个逻辑运算
线性序列时,人就容易理解。外延分支和
外延大的循环都违反了处理的线性。结构
化构造的直接实现有助于编程语言的线性。
工程特性
易转换性
编译效率
可移植性
是否有开发工具
源程序的可维护性
2、语言的分类
? 基本语言 (Fortran,Basic,Algol,Cobol)
? 结构化程序语言 (Pascal,C)
? 专用语言
传统分法的可分为:
按“代”来分,可分为:
第一代语言,主要特征,面向机器,代表语
言是机器语言 (使用的是绝对地址码、绝对操作
码和存储空间分配 )、汇编语言 。
第二代语言, 50年代 ---60年代初,主要特征,
脱离机器面向算法过程的高级语言。有变量、赋
值、子程序、函数调用概念,有少量的基本数据
类型,有限的循环套和一般的递归调用等。代表
语言,FORTRAN,ALGOL,COBOL,BASIC(第三代语言
的基础 )
第三代语言,也称结构化编程语言,60年
代 —70年代,特点是:具有很强的过程和数据
结构化的能力。 可分为三类,通用高级语言
(C,Pascal,Ada美国的三军通用语言 )、面向
对象高级语言 (C++,Objective-C,Smalltalk,
Eiffel)、专用语言 (LISP,PROLOG,APL和
FORTH)
第四代语言, 70年代后,主要特征是用户极
端友好、声明式、交互式和非过程式的编程语言、
高效的程序代码、智能缺省假设、完备的数据库、
应用程序生成器。代表语言,FOXPRO,VFP,VC、
VB等等。
4GL溶入了许多新发展的技术,如,事件驱动、
分布式数据共享、多媒体技术,4GL是一个交互
式的程序设计环境。
3、程序设计语言的选择
一般来说来,高级语言明显优于汇编语言,
因此,除了在很特殊的应用领域 (例如,对程序
执行时间和使用的空间都有很严格限制的情况;
体系结构特殊的微处理机,以致在这类机器上通
常不能实现高级语言编译程序 ),或者大型系统
中执行时间非常关键的 (或直接依赖于硬件的 )一
小部分代码需要用汇编语言书写之外,其他程序
宜用高级语言书写。
为了降低软件开发和维护的总成本, 提高软
件的可靠性, 选择程序设计语言的理想标准是:
( 1) 选用的高级语言应该有理想的模块化机
制, 以及可读性好的控制结构和数据结构;
( 2) 选用的语言应该使编译程序能够尽可能
多地发现程序中的错误;
( 3) 选用的语言应该具有良好的独立编译机
制 。
但是在实际选用语言时不能仅仅考虑理论上
的标准,还必须同时考虑实用方面的各种限制。
二,编码风格
良好的源程序代码应该是的逻辑简明清晰、易
读易懂,为了做到这一点,应该遵循下述规则:
1,
所谓程序内部的文档包括:
?恰当的 标识符
?适当的 注解语句
?程序的 组织视觉
1、标识符指变量的命名。
2、注释语句分为两类:
序言性注释语句
描述性注释语句
3、组织视觉是指写程序的形式布局。如,
缩格风格。
2.
虽然在设计期间已经确定了数据结构的组织
和复杂程度,然而数据说明的风格却是在写程序
时确定的。
为了使数据更容易理解和维护,遵循一些比
较简单的原则是必要的。
3.
基本原则:简明扼要
每个语句都应该简单而直接,不能为了提高效率而使
程序变得过分复杂。
一行只写一条语句。
4 输入 /
? 对所有输入数据都进行检验;
? 检查输入项重要组合的合法性;
? 保持输入格式简单;
? 使用数据结束标记,不要要求用户指定数据
的数目;
? 明确提示交互式输入的请求,详细说明可用
的选择或边界数值;
? 当程序设计语言对格式有严格要求时,应保
持输入格式一致;
? 设计良好的输出报表;
? 给所有输出数据加标志。
5,效率
效率主要指 处理机时间 和 存储器容量 两个方
面 。 虽然值得提出提高效率的要求, 但是在进一
步讨论这个问题之前应该记住三条原则,首先,
效率是性能要求, 因此应该在需求分析阶段确定
效率方面的要求 。 其次, 效率是靠好设计来提高
的 。 第三, 程序的效率和程序的简单程度是一致
的 。 不要牺牲程序的清晰性和可读性来不必要地
提高效率 。
第二节 软件测试基础
无论怎样强调软件测试的重要性和它对软件
可靠性的影响都不过分。在开发大型软件系统的
漫长过程中,面对着极其错综复杂的问题,人的
主观认识不可能完全符合客观现实,与工程密切
相关的各类人员之间的通信和配合也不可能完美
无缺,因此,在软件生命周期的每个阶段都不可
避免地会产生差错。
我们力争在每个阶段结束之前进行严格的技
术审查,尽可能及早发现并纠正差错。但是,经
验表明审查并不能发现所有差错,此外在编码过
程中还不可避免地会引入新的错误。如果在软件
投入生产性运行之前,没有发现并纠正软件中的
大部分差错,则这些差错迟早会在生产过程中暴
露出来,那时不仅改正这些错误的代价更高,而
且往往会造成很恶劣的后果。
测试的目的就是在软件投入生产性运行之前,
尽可能多地发现软件中的错误。
目前软件测试仍然是保证软件质量的关键步
骤,它是对软件规格说明、设计和编码的最后复
审。
大量统计资料表明,软件测试的工作量往往
占软件开发总工作量的 70%以上。极端情况下,
测试那种关系人的生命安全的软件所花费的成本,
可能相当于软件工程其他步骤总成本的 3~ 5倍。
因此,必须高度重视软件测试工作,绝不要以为
写出程序之后软件开发工作就接近完成了,实际
上,大约还有同样多的开发工作量需要完成。
测试目的 是发现软件中的错误,但是,发现
错误并不是软件开发的最终目的。软件工程的根
本目标是开发出高质量的完全符合用户需要的软
件。因此,通过测试发现错误之后还必须诊断并
改正错误,这就是调试,调试是测试阶段最困难
的工作。在对测试结果进行收集和评价的时候,
软件所达到的可靠性也开始明朗了。软件可靠性
模型使用故障率数据,估计软件将未来出现故障
的情况并预测软件的可靠性。
一, 测试目标
G,Myers给出了关于测试的一些规则, 这些
规则也可以看作是测试的目标或定义:
测试是为了发现程序中的错误而执行程序的
过程;好的测试方案是极可能发现迄今为止尚未
发现的错误的测试方案;成功的测试是发现了至
今为止尚未发现的错误的测试。
由于测试的目标是暴露程序中的错误,从心
理学角度看,由程序的编写者自己进行测试是不
恰当的。因此,在综合测试阶段通常由其他人员
组成测试小组来完成测试工作。
测试的目的在于寻找错误,并且找出的错误
越多越好。那么,能不能把所有隐藏的错误全都
找出来呢?或者说能不能把所有可能做的测试无
遗漏地一一做完呢?这是不可能的。测试只能进
行有限次,一次测试只是一次抽样。所以,在不
论多少次测试中,如果都没有发现错误,也不能
证明软件没有错误。
x
y
z
(X,y,z是 16位二进制数 )
每个数有 216种,三个数的组合数有
216× 216× 216 ≈248 ≈3× 1014种,假定每次执行一次程序
需要一毫秒,执行 3× 1014次大约需要一万年 ! 才能测试完
毕。不可能进行穷尽测试。只能进行有限次的抽样测试。
一个好的测试,既要尽可能发现更多的错误,
又要经济,即要提高测试效率。要做到这点,关
键在于设计测试用例,必须精心设计测试用例,
挑选尽可能少的测试数据,使得采用这些测试数
据能够达到最佳的效果,或说能够高效率地把隐
藏的错误揭露出来。
二, 测试对象
软件测试并不等于程序测试。软件测试应贯
穿于软件定义与开发的整个期间。因此,需求分
析、概要设计、详细设计以及程序编码等各阶段
所得到的文档,包括需求分析规格说明书、概要
设计规格说明、详细设计规格说明以及源程序,
都应成为软件测试的对象。软件测试不仅限在程
序测试的狭小范围内,而应考虑到其他阶段的所
有工作。
需求分析
程序编码
详细设计
概要设计
需求规格说明书
概要设计规格说明
源程序代码
详细设计规格说明
测试对象
三, 黑盒测试和白盒测试
黑盒测试和白盒测试是设计测试用例的两种
方法。
黑盒测试法 把程序看成一个黑盒子,完全不
考虑程序的内部结构和处理过程。
黑盒测试是在程序接口进行的测试。
它只检查程序功能是否能按照规格说明书的
规定正常使用,程序是否能适当地接收输入数据
产生正确的输出信息,并且保持外部信息 (如,
数据库或文件 )的完整性,完全不考虑程序内部
的逻辑结构和内部特征。
输入 输入
黑盒测试主要是为了发现以下六类错误:
1,是否有不正确或遗漏了的功能?
2,在接口上,输入能否正确地接受?能否
输出正确的结果?
3,性能上是否能够满足要求?
4,是否有初始化或终止性错误?
5,界面错误?
6,数据结构错误或外部数据库访问错误?
白盒测试法 的前提是可以把程序看成装在一
个透明的白盒子里,也就是完全了解程序的结构
和处理过程。
白盒测试又称为结构测试或称为逻辑驱动测
试。
这种方法按照程序内部的逻辑测试程序,检
验程序中的每条通路是否都能按预定要求正确
工作。
测试内部程序
白盒测试主要对程序进行如下检查:
1,对程序模块的所有独立的执行路径至少
测试一次;
2,对所有的逻辑判定,取, 真,,与取
,假, 的两种情况都能到少测试一次;
3,在循环的边界和运行界限内体;
4,测试内部数据结构的有效性。
四, 测试准则
为了能设计出有效的测试方案,软件人员必
须充分理解并正确运用指导软件测试的基本准则,
主要的测试准则如下:
( 1)及早地和不断地进行软件测试;
( 2)测试前要认定被测软件有错,充分注意
测试中的集群现象;
( 3)所有的测试都应该以软件需求规格说明
书为准需求;
( 4) 设计测试用例时, 应当兼顾合理输入与
不合理输入数据;
( 5) 穷举测试是不可能的 。
( 6) 为了达到最佳的测试效果, 应该由独立
的第三方来从事测试工作 。
测试准则:
五, 测试信息流
测试信息流如图所示, 测试有二类输入:
测试
排错
可靠性
分析
结果
分析
测
试
配
置
测
试
工
具
测
试
结
果
预
期
结
果
出 错
出
错
概
率
数
据
改正的软件
预测的可靠性
测试信息流
第三节 白盒测试
通常又把测试数据和预期的输出结果称为 测
试用例 。
白盒测试的设计测试用例方法有:
逻辑覆盖、基本路径测试、条件测试、数据
流测试、循环测试等五种技术。
所谓 测试方案 包括具体的测试目的 (例如,要
测试的具体功能 ),应该输入的测试数据和预期
的输出结果。
不同的测试数据发现程序错误的能力差别很
大,为了提高测试效率降低测试成本,应该选用
高效的测试数据。
因为不可能进行穷尽的测试,选用少量, 最
有效的, 测试数据,做到尽可能完备的测试就更
重要了。
一、逻辑覆盖
所谓逻辑覆盖是一系列对程序内部逻辑测试
过程的总称。主要有:
语句覆盖、判定覆盖、条件覆盖、
判定 /条件覆盖、组合条件覆盖等。
下面以例说明。
例如,,它的源程序如下:
procedure example (A,B,real ; var X:
real) ;
begin
if (A>1) and (B=0)
then X,= X/A;
if(A=2) or (X>1)
then X,= X+1
end;
被测试模块的流程图
入 口
A = 2
o r X > 1
X = X / A
X = X + 1
返 回
A > 1
a n d B = 0
T
F
F
T
1
7
6
5
4
3
2
S
a
b
d
c
e
为了暴露程序中的错误, 至少每个语句应该
执行一次 。 语句覆盖的含义是选择足够多的测试
数据, 使被测程序中每个语句至少执行一次 。
测试用例的设计格式,( A,B,x)
上例的语句覆盖的测试用例是,( 2,0,4) 。
1,语句覆盖
入口
A= 2
or X>1
X= X/A
X=X+1
返回
A> 1
and B= 0
T
F
F
T
1
7
6
5
4
3
2
S
a
b
d
c
e
2.
判定覆盖又叫分支覆盖, 它的含义是, 不
仅每个语句必须至少执行一次, 而且每个判定的
每种可能的结果都应该至少执行一次, 也就是每
个判定的每个分支都至少执行一次 。
上例的判定覆盖的测试用例是:
( 2,0,4)和( 0,1,4)。
3
条件覆盖的含义是, 不仅每个语句至少执
行一次, 而且使判定表达式中的每个条件都取到
各种可能的结果 。
上例的条件覆盖的测试用例是:
( 2,0,4) 和 ( 1,1,1) 。
既然判定覆盖不一定包含条件覆盖,
条件覆盖也不一定包含判定覆盖, 自然会提出一
种能同时满足这两种覆盖标准的逻辑覆盖, 这就
是判定 /条件覆盖 。 它的含义是, 选取足够多的
测试数据, 使得判定表达式中的每个条件都取到
各种可能的值, 而且每个判定表达式也都取到各
种可能的结果 。
上例的判定 /条件覆盖的测试用例是:
( 2,0,4) 和 ( 1,1,1) 。
4.判定 /条件覆盖
5.
条件组合覆盖是更强的逻辑覆盖标准, 它
要求选取足够多的测试数据, 使得每个判定表达
式中条件的各种可能组合都至少出现一次 。 上例
的条件组合是:
( 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
上例的条件组合覆盖的测试用例是:
( 2,0,4)
( 1,1,1)
( 2,1,1)
( 1,0,2)
二, 基本路径测试
基本路径测试是 Tom McCabe提出的一种白盒
测试技术。使用这种技术设计测试用例步骤:
1、计算详细设计结果的逻辑复杂度;
2、定义独立执行路径的基本集合;
3、从该基本集合导出的测试用例可以保证程
序中的每条语句至少执行一次,而且每个条件在
执行时都将分别取 true(真 )和 false(假 )值。
1,根据过程设计结果画出相应的流图
PROCEDURE average; /*这个过程计算不超过 100个在
规定值域内的有效数字的平均值;同时计算有效数字的总
和及个数 。 */
INTERFACE RETURNS average,total input,total
valid;
INTERFACE ACCEPTS value,minimum,maximum;
TYPE value? 1...100? 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,IFtotal valid> 0
11,THEN average= sum/total valid;
12,ELSEaverage= -999
13,ENDIF
END average
1
12 11
10
9
78
6
5
4
2
3
13
求平均值过程的流图
2,计算流图的环形复杂度
环形复杂度定量度量程序的逻辑复杂性。有
了描绘程序控制流的流图之后,可以用下述三种
方法之一来计算环形复杂度。
( 1) 流图中的区域数 (包括有界和无界 )等于环
形复杂度 。
( 2) 流图 G的环形复杂度 V(G)= E-N+2p,其中 E是
流图中边的条数, N是流图中节点数,p是联结成分的
个数 。
( 3) 流图 G的环形复杂度 V(G)= Q+1,
其中 Q是流图中判定节点的数目 。
使用上述任何一种方法,都可以计算出上例所示
流图的环形复杂度为 6。
3,确定线性独立路径的基本集合
所谓独立路径是指至少引入程序的一个新处
理语句集合或一个新条件的路径 。 用流图术语描
述, 独立路径至少包含一条在定义该路径之前不
曾用过的边 。
使用基本路径测试法设计测试用例时,程序
的环形复杂度决定了程序中独立路径的数量,而
且这个数是确保程序中所有语句至少被执行一次
所需的测试数量的上界。
对于上图所描述的求平均值过程来说, 由于
环形复杂度为 6,因此共有 6条独立路径 。 例如,
下面列出了 6条独立路径:
路径 1,1-2-10-11-13
路径 2,1-2-10-12-13
路径 3,1-2-3-10-11-13
路径 4,1-2-3-4-5-8-9-2- …
路径 5,1-2-3-4-5-6-8-9-2- …
路径 6,1-2-3-4-5-6-7-8-9-2- …
路径 4,5,6后面的省略号 (...)表示, 可以
后接通过控制结构其余部分的任意路径 (例如,
10-11-13)。
通常在导出测试用例时,识别出判定节点是
很有必要的。本例中节点 2,3,5,6和 10是判定
节点。
4.设计可强制执行基本集合中每条路径的测
应该选取数据使得在测试每条路径时都适当
地设臵好了各个判定节点的条件 。 可以测试上述
路径 1
value? k? =有效输入值, 其中 k< i(i的定
义在下面 )
value? i? = -999,其中 2≤i≤ 100
预期结果:基于 k的正确平均值和总数
注意, 路径 1无法独立测试, 必须作为路径 4、
5和 6的一部分来测试 。
路径 2
value? 1? = -999
预期结果,average= -999,其他都保持初始
值 。
路径 5
value? i? =有效输入值, 其中 i< 100
value? k? > maximum,其中 k< i
预期结果:其于 k的正确平均值和总数
路径 6
value? i? =有效输入值, 其中 i< 100
预期结果:正确的平均值和总数
三, 条件测试
尽管基本路径测试技术简单而且高效, 但是
仅有这种技术还不够, 还需要使用其他控制结构
测试技术, 才能进一步提高白盒测试的质量 。
用条件测试技术设计出的测试用例,能够检
查程序模块中包含的逻辑条件。一个简单条件是
一个布尔变量或一个关系表达式,在布尔变量或
关系表达式之前还可能有一个 NOT(,┐,)算符。
E1<关系算符> E2
其中, E1和 E2是算术表达式, 而<关系算符>
是下列算符之一:, <,,, ≤,,, =,,
,≠,,, >, 或, ≥, 。 复合条件由两个或多
个简单条件, 布尔算符和括弧组成 。 布尔算符有
OR(“|, ),AND(“&”)和 NOT(,┐,)。 不包含关
系表达式的条件称为布尔表达式 。
在上述种种条件测试技术的基础上,K.C.Tai
提出了一种被称为 BRO(Branch and Relational
Operalor)测试的条件测试策略。
如果在条件中所有布尔变量和关系算符都只
出现一次而且没有公共变量,则 BRO测试保证能
发现该条件中的分支错和关系算符错。
BRO测试利用条件 C的条件约束来设计测试用
例 。 包含 n个简单条件的条件 C的条件约束定义为
(D1,D2,…, Dn),其中 D i(0< i≤n) 表示条件
C中第 i个简单条件的输出约束 。 如果在条件 C的
一次执行过程中, C中每个简单条件的输出都满
足 D中对应的约束, 则称 C的这次执行覆盖了 C的
条件约束 D。
对于布尔变量 B来说, B的输出约束指出, B必
须是真 (t)或假 (f)。 类似地, 对于关系表达式来
说, 用符号>, =和<指定表达式的输出约束 。
作为一个例子,
C1,B1& B2
其中,B1和 B2是布尔变量。 C1的条件约束形式
为 (D1,D2),其中 D1和 D2中的每一个都是, t”或
,f”。值 (t,f)是 C1的一个条件约束,并由使 B1
值为真 B2值为假的测试所覆盖。 BRO测试策略要求,
约束集{ (t,t),(f,t),(t,f)}被 C1的执行
所覆盖。如果 C1因布尔算符错误而不正确,则至
少上述约束集中的一个约束将迫使 C1失败。
四, 数据流测试
数据流测试方法根据程序中变量定义和使用
的位臵, 选择程序的测试路径 。 为了说明数据流
测试方法, 假设已赋予程序每条语句一个唯一的
语句号, 而且每个函数都不修改它的参数或全局
变量 。 对于语句号为 S的语句
DEF(S)={ X|语句 S包含变量 X的定义 }
USE(S)={ X|语句 S使用变量 X}
如果 S是 if或循环语句,则它的 DEF集为空,
而它的 USE集取决于 S的条件。如果存在从语句 S
到语句 S′ 的路径,而且在该路径中不包含 X的任
何其他定义,则称变量 X在语句 S中的定义在语句
S′ 仍然有效。
变量 X的定义 ——使用链 (或称为 DU链 )的形
式为 ? X,S,S′ ?, 其中 S和 S′ 是语句号, X在
集合 DEF(S)和 USE(S′ )中, 而且在语句 S中对 X的
定义在语句 S′ 仍然有效 。
一种简单的数据流测试策略要求, 每个 DU链
至少被覆盖一次, 这种策略称为 DU测试策略 。
五, 循环测试
循环测试是一种白盒测试技术,它专注于测
试循环结构的有效性。在结构化的程序中通常只
有三种循环,分别是 简单循环, 串接循环 和 嵌套
循环。
1.
应该使用下列测试集来测试简单循环, 其中 n
是允许通过循环的最大次数 。
通过循环 m次, 其中 m< n-1
通过循环 n-1,n,n+1次。
简单循环 嵌套循环 串接循环
三种循环
2.
如果把简单循环的测试方法直接应用到嵌套
循环, 可能的测试数就会随嵌套层数的增加按几
何级数增长, 这会导致不切实际的测试数目 。
B.Beizer提出了一种能减少测试数的方法 。
( 1) 从最内层循环开始测试, 把所有其他循环
都设臵为最小值;
( 2) 对最内层循环使用简单循环测试方法, 而
使外层循环的迭代参数 (例如, 循环计数器 )取
最小值, 并为越界值或非法值增加一些额外的
( 3) 由内向外, 对下一个循环进行测试, 但保
持所有其他外层循环为 最小值, 其他嵌套循
环为, 典型,
( 4) 继续进行下去, 直到测试完所有循 。
3,串接循环
如果串接循环的各个循环都彼此独立, 则可
以使用前述的测试简单循环的方法来测试串接循
环 。 但是, 如果两个循环串接, 而且第一个循环
的循环计数器值是第二个循环的初始值, 则这两
个循环并不是独立的 。 当循环不独立时, 建议使
用测试嵌套循环的方法来测试串接循环 。
第四节 黑盒测试技术
黑盒测试着重测试软件的功能需求,也就是
说,黑盒测试让软件工程师设计出能充分检查程
序所有功能需求的输入条件集。黑盒测试并不能
取代白盒测试技术,它是与白盒测试互补的方法,
它很可能发现白盒测试不易发现的其他不同类型
的错误。
白盒测试在测试过程的早期阶段进行,而黑
盒测试主要用于测试过程的后期。黑盒测试故意
不考虑程序的控制结构,而把注意力集中于信息
域。
黑盒测试技术主要有:
等价分类法,边界值分析法、错误推断法
一,
等价分类法是一种黑盒测试方法,这种方法
把程序的输入域划分成若干个等价数据类,据此
可以导出测试用例。
如果把所有可能的输入数据 (有效的和无效的 )
划分成若干个等价类,则可以合理地做出下述假
定:
每类中的一个典型值在测试中的作用与这一
类中所有其他值的作用相同。
因此,可以从每个等价类中只取一组数据作
为测试数据。这样选取的测试数据最有代表性,
最可能发现程序中的错误。
使用等价划分法设计测试方案,首先需要划
分输入数据的等价类,为此需要研究程序的功能
说明,从而确定输入数据的有效等价类和无效等
价类。
在确定输入数据的等价类时常常还需要分析
输出数据的等价类,以便根据输出数据的等价类
导出对应的输入数据等价类。
划分等价类需要经验, 下述几条启发式规则
可能有助于等价类的划分 。
1,如果规定了输入值的范围, 则可划分出一
个有效的等价类 (输入值在此范围内 ),两个无效
的等价类 (输入值小于最小值或大于最大值 )。
2、如果规定了输入数据的个数,则类似地也
可以划分出一个有效的等价类和两个无效的等价
类。
3,如果规定了输入数据的一组值, 而且程序
对不同输入值做不同处理, 则每个允许的输入值
是一个有效的等价类, 此外还有一个无效的等价
类 (任一个不允许的输入值 )。
4、如果规定了输入数据必须遵循的规则,则
可以划分出一个有效的等价类 (符合规则 )和若干
个无效的等价类 (从各种不同角度违反规则 )。
5,如果规定了输入数据为整型, 则可以划分
出正整数, 零和负整数等三个有效类 。
6,如果程序的处理对象是表格, 则应该使用
空表, 以及含一项或多项的表 。
划分出等价类以后, 等价类设计测试方案时
主要使用下面两个步骤 。
1)设计一个新的测试方案以尽可能多地覆盖
尚未被覆盖的有效等价类,复重这一步骤直到所
2)设计一个新的测试方案,使它覆盖一个而
且只覆盖一个尚未被覆盖的无效等价类,重复这
一步骤直到所有无效等价类都被覆盖为止。
二, 边界值分析
经验表明,处理边界情况时程序最容易发生
错误。例如,许多程序错误出现在下标、纯量、
数据结构和循环等的边界附近。因此,设计使程
序运行在边界情况附近的测试方案,暴露出程序
错误的可能性更大一些。
使用边界值分析方法设计测试方案首先应该
确定边界情况,这需要经验和创造性,通常输入
等价类和输出等价类的边界,就是应该着重测试
的程序边界情况。选取的测试数据应该刚好等于、
刚刚小于和刚刚大于边界值。也就是说,按照边
界值分析法,应该选取刚好等于、稍小于和稍大
于等价类边界值的数据作为测试数据,而不是选
取每个等价类内的典型值或任意值作为测试数据。
三, 错误推测
错误推测法在很大程度上靠直觉和经验进行。
它的基本想法是列举出程序中可能有的错误和容
易发生错误的特殊情况,并且根据它们选择测试
方案。
第五节 测试策略
一、测试种类
单元测试 。 单元测试大量使用白盒测试技术,
检查模块控制结构中的特定路径, 以确保做到完
全覆盖并发现最大数量的错误 。
集成测试。 在装配的同时进行测试,集成测
试同时解决程序验证和程序构造这两个问题。在
集成过程中最常用的是黑盒测试用例设计技术,
当然,为了保证覆盖主要的控制路径,也可能使
用一定数量的白盒测试。
高级测试 。在软件集成完成之后,还需要进
行一系列高级测试。
确认测试 。必须测试在需求分析阶段确定下
来的确认标准,确认测试是对软件满足所有功能
的、行为的和性能的需求的最终保证。在确认测
试过程中仅使用黑盒测试技术。
二, 单元测试
通常,单元测试和编码属于软件工程过程的
同一个阶段。在编写出源程序代码并通过了编译
程序的语法检查之后,可以应用人工测试和计算
机测试这样两种类型的测试,完成单元测试工作。
这两种类型的测试各有所长,互相补充。人工测
试和计算机测试。
三, 集成测试
集成测试是测试和组装软件的系统化技术,
在把模块按照设计要求组装起来的同时进行测试,
主要目标是发现与接口有关的问题。
模块组装
成程序的
两种方法
渐增式测试
非渐增式测试
自低向上
自顶向下
自低向上
自顶向下
1.
自顶向下的集成 (结合 )方法是一个日益为人
们广泛采用的组装软件的途径。从主控制模块
(主程序 )开始,沿着软件的控制层次向下移动,
从而逐渐把各个模块结合起来。在把附属于 (以
及最终附属于 )主控制模块的那些模块组装到软
件结构中去时,或者使用深度优先的策略,或者
使用宽度优先的策略。
把模块结合进软件结构的具体过程由下述四
1) 对主控制模块进行测试, 测试时用 存根程
序
2)根据选定的结合策略 (深度优先或宽度优
先 ),每次用一个实际模块代换一个存根程序 (新
结合进来的模块往往又需要新的 存根程序 )
3)在结合进一个模块的同时进行测试;
4) 为了保证加入模块没有引进新的错误, 可
能需要进行回归测试 (即, 全部或部分地重复以
前做过的测试 )。
从第二步开始不断地重复进行上述过程,直
到构造起完整的软件结构为止。
2.
自底向上测试从, 原子, 模块 (即在软件结构
最低层的模块 )开始组装和测试。因为是从底部
向上结合模块,总能得到需要的下层模块处理功
能,所以不需要存根程序。
用下述步骤可以实现自底向上的结合策略:
1)把低层模块组合成实现某个特定的软件子
功能的模块群 ( 族 )
2) 开发一个 驱动模块 (用于测试的控制程序 ),
协调测试数据的输入和输出;
3)对每个模块群 ( 族 ) 进行测试;
4)去掉测试使用的 驱动程序, 用较高层模块
把模块群 ( 族 ) 组合成为完成更大功能的新模块
群 ( 族 ) 。
从第一步开始循环执行上面各步骤,直至整
个程序构造完成。
3,回归测试
每当一个新模块作为集成测试的一部分加进
来的时候,软件就发生了变化:建立了新的数据
流路径,可能出现了新的 I/O操作,激活了新的
控制逻辑。这些变化可能使原来工作正常的功能
出现问题。在集成测试的范畴中,所谓 回归测试
是指重新执行已经做过的测试的某个子集,以保
证上述这些变化没有带来非预期的副作用。
4,不同集成测试策略的比较
自顶向下 测试方法的主要 优点 是不需要测试
驱动程序,能够在测试阶段的早期实现并验证系
统的主要功能,而且能在早期发现上层模块的接
口错误。
自顶向下 测试方法的主要 缺点 是需要存根程
序,可能遇到与此相联系的测试困难,低层关键
模块中的错误发现较晚,而且用这种方法在早期
不能充分展开人力。
可以看出,自底向上测试方法的优缺点与上
述自顶向下测试方法的优缺点刚好相反。
四,
为了把握各个环节的正确性,需要进行各种
确认 和 验证 工作。确认测试也称为验收测试,它
的目标是验证软件的有效性。
用 户 要 求
用 户 要 我 做 什
么
运 行 结 果
计 算 机 程 序 运
行 结 果
需 求 说 明 书
分 析 员 可 以 提
供 什 么?
源 程 序
程 序 员 要 让 计
算 机 做 什 么?
设 计 说 明 书
设 计 员 要 让 计
算 机 做 什 么?
相 符 吗?
理 解 正 确 性
表 达 正 确 性
运 行 正 确 性
输 入 正 确 性
理 解 正 确 性
编 码 正 确 性
理 解 正 确 性
设 计 正 确 性
表 达 正 确 性
①
②
③
④
⑤
软件生存期各个阶段之间需要保持的正确性
验证指的是保证软件正确地实现了某一特定
要求的一系列活动,验证是试图证明在软件生存
期各个阶段以及阶段间的逻辑协调性、完备性和
正确性。
确认指的是保证软件的实现满足了用户需求
的一系列活动。其 目的 是证实在一个给定的外部
环境中软件的逻辑正确性。它包括 需求规格说明
的确认 和 程序的确认,而程序的确认又分为静态
确认与动态确认。 静态确认 一般不在计算机上实
际执行程序,而是通过人工分析或程序正确性证
明来确认程序的正确性; 动态确认 主要通过动态
分析和程序测试来检查程序的执行状态,以确认
程序是否有问题。
确认与验证工作都属于软件测试。在对需求
理解与表达的正确性、设计与表达的正确性、实
现与表达的正确性的验证中,任何一个环节上发
生了问题都有可能在软件测试中表现出来。
第六节 调试
调试 (也称为纠错 )作为成功的测试的后果而
出现, 也就是说, 调试是在测试发现错误之后排
除错误的过程 。
一, 调试过程
调试不是测试,但是它总是发生在测试之后。
如图 5-10所示,调试过程从执行一个测试用例开
始,评估测试结果,如果发现实际结果与预期结
果不一致,则这种不一致就是一个症状,它表明
在软件中存在着隐藏的问题。调试过程试图找出
产生症状的原因,以便改正错误。
二, 调试途径
无论采用什么方法,调试的根本目标都是寻
找软件错误的原因并改正之。这个目标是通过把
系统地评估、直觉和运气组合起来实现的。一般
?蛮干法;
?回溯法;
?原因排除法
三, 可靠性的基本概念
1.
软件可靠性是指程序在给定的时间间隔内,
按照规格说明书的规定, 成功地运行的概率 。
2,软件的可用性
软件可用性是指程序在给定的时间点,按照
规格说明书的规定,成功地运行的概率。