AMALL=Z
GOTO70
50SMALL=Y
GOTO70
60SMALL=X
70CONTINUE
SMALL=X;
IF(Y
SMALL=Y;
IF(Z
SMALL=Z;
例9:
避免使用空ELSE和IF…THENIF…语句
if(char>=’a’)
if(char<=’z’)
cout<<“Thisisaletter.”;
else
cout<<“Thisisnotaletter.”;
if(char>=’a’&&char<=’z’)
cout<<“Thisisaletter.”;
else
cout<<“Thisisnotaletter.”;
例10:
少用否定条件
if(!
(char<’0’||char>’9’))
if(char>=‘0’&&char<=‘9’)
7.2软件测试基础
7.2.1软件测试的目标
测试是为了发现程序中的错误而执行程序的过程;
好的测试方案是极可能发现迄今为止尚未发现的错误的测试方案;
成功的测试是发现了至今为止尚未发现的错误的测试。
所有测试都应该能追溯到用户需求;
应该远在测试开始之前就制定出测试计划;
把Pareto原理应用到软件测试中;
应该从“小规模”测试开始,并逐步进行“大规模”测试;
穷举测试是不可能的;
为了达到最佳的测试效果,应该由独立的第三方从事测试工作。
7.2.2软件测试准则
7.2.3测试方法
黑盒测试(功能测试):
把程序看作一个黑盒子;
完全不考虑程序的内部结构和处理过程;
是在程序接口进行的测试。
白盒测试(结构测试):
把程序看成装在一个透明的盒子里;
测试者完全知道程序的结构和处理算法;
按照程序内部的逻辑测试程序,检测程序中的主要执行通路是否都能按预定要求正确工作。
黑盒测试不可能实现穷尽测试:
假设有程序P,输入量微A和B,输出量为C。
如果计算机的字长为32位,A和B的数据类型都是整数类型。
将A和B的可能取值进行排列组合,输入数据的可能性有:
232×232=264种。
假设这个程序执行一次需要1毫秒,要完成所有的测试,计算机需要连续工作5亿年。
白盒测试也不能实现穷尽测试:
图中所示的一个小程序的控制流程。
曲线代表执行次数不超过20的循环,循环体中共有5条通路。
可能执行的路径有520条,近似为1014条可能的路径。
如果完成一个路径的测试需要1毫秒,那么整个测试过程需要3170年。
黑盒测试与白盒测试优缺点比较:
䦋㌌㏒㧀좈琰茞ᓀ㵂Ü
黑盒测试
白盒测试
优点
①适用于各阶段测试
②从产品功能角度测试
③容易入手生成测试数据
①可构成测试数据使特定程序部分得到测试
②有一定的充分性度量手段
③可获较多工具支持
缺点
①某些代码得不到测试
②如果规格说明有误,则无法发现
③不易进行充分性测试
①通常不易生成测试数据
②无法对未实现规格说明的部分进行测试③工作量大,通常只用于单元测试,有应用局限
性质
一种确认技术,回答“我们在构造一个正确的系统吗?
”
一种验证技术,回答“我们在正确地构造一个系统吗?
”
7.2.4测试步骤
1.模块测试(单元测试)
保证每个模块作为一个单元能正确运行;
发现的往往是编码和详细设计的错误。
2.子系统测试
把经过单元测试的模块放在一起形成一个子系统来测试;
着重测试模块的接口。
3.系统测试
把经过测试的子系统装配成一个完整的系统来测试;
发现的往往是软件设计中的错误,也可能发现需求说明中的错误;
不论是子系统测试还是系统测试,都兼有检测和组装两重含义,通常称为集成测试。
4.验收测试(确认测试)
把软件系统作为单一的实体进行测试;
它是在用户积极参与下进行的,而且可能主要使用实际数据(系统将来要处理的信息)进行测试;
发现的往往是系统需求说明书中的错误。
5.平行运行
同时运行新开发出来的系统和将被它取代的旧系统;
比较新旧两个系统的处理结果;
可以在准生产环境中运行新系统而又不冒风险;
用户能有一段熟悉新系统的时间;
可以验证用户指南和使用手册之类的文档;
能够以准生产模式对新系统进行全负荷测试,可以用测试结果验证性能指标。
7.2.5测试阶段的信息流
输入信息有两类:
软件配置,包括需求说明书、设计说明书和源程序清单等;
测试配置,包括测试计划和测试方案。
7.3单元测试
单元测试集中检测模块;
单元测试和编码属于软件过程的同一个阶段;
可以应用人工测试和计算机测试这样两种不同类型的测试方法;
单元测试主要使用白盒测试技术,对多个模块的测试可以并行地进行。
7.3.1测试重点
模块接口
局部数据结构
重要的执行通路
出错处理通路
边界条件
7.3.2代码审查
由审查小组正式进行测试称为代码审查;
可查出30%~70%的逻辑设计错误和编码错误;
审查小组组成:
组长
程序的设计者
程序的编写者
程序的测试者
一次审查会上可以发现许多错误,可以减少系统验证的总工作量。
7.3.3计算机测试
必须为每个单元测试开发驱动程序和(或)存根程序。
驱动程序是一个“主程序”,它接收测试数据,传送给被测试的模块,并且印出有关的结果。
存根程序代替被测试的模块所调用的模块。
它使用被它代替的模块的接口,可能做最少量的数据操作,印出对入口的检验或操作结果,并且把控制归还给调用它的模块。
驱动程序和存根程序代表开销,通常并不把它们作为软件产品的一部分交给用户。
7.4集成测试
集成测试是测试和组装软件的系统化技术,主要目标是发现与接口有关的问题。
由模块组装成程序时有两种方法:
非渐增式测试方法
渐增式测试方法
非渐增式测试方法:
先分别测试每个模块,再把所有模块按设计要求放在一起结合成所要的程序;
非渐增式测试一下子把所有模块放在一起,并把庞大的程序作为一个整体来测试,测试者面对的情况十分复杂。
在庞大的程序中想要诊断定位一个错误是非常困难的,改正错误更是极端困难,而且一旦改正一个错误之后,马上又会遇到新的错误。
渐增式测试方法:
把下一个要测试的模块同已经测试好的那些模块结合起来进行测试;
测试完以后再把下一个应该测试的模块结合进来测试,每次增加一个模块;
实际上同时完成单元测试和集成测试;
把程序划分成小段来构造和测试,在这个过程中比较容易定位和改正错误;
渐增方式有两种集成策略:
自顶向下
自底向上
7.4.1自顶向下集成
从主控制模块开始,沿着程序的控制层次向下移动,逐渐把各个模块结合起来。
在把附属于主控制模块的那些模块组装到程序结构中去时,或者使用深度优先的策略,或者使用宽度优先的策略。
深度优先:
先组装在软件结构的一条主控制通路上的所有模块。
宽度优先:
沿软件结构水平地移动,把处于同一个控制层次上的所有模块组装起来。
按深度优先策略组装
按宽度优先策略组装
把模块结合进软件结构的过程由下述4个步骤完成:
第一步,对主控制模块进行测试,测试时用存根程序代替所有直接附属于主控制模块的模块;
第二步,根据选定的结合策略(深度优先或宽度优先),每次用一个实际模块代换一个存根程序(新结合进来的模块往往又需要新的存根程序);
第三步,在结合进一个模块的同时进行测试;
第四步,为了保证加入模块没有引进新的错误,可能需要进行回归测试(即,全部或部分地重复以前做过的测试)。
从第二步开始不断地重复进行上述过程,直到构造起完整的软件结构为止。
优点:
能够在测试的早期对主要的控制或关键的抉择进行检验。
如果选择深度优先的结合方法,可以在早期实现软件的一个完整的功能并且验证这个功能。
缺点:
存根程序代替了低层次的模块,在软件结构中没有重要的数据自下往上流。
用下述步骤可以实现自底向上的结合策略:
第一步,把低层模块组合成实现某个特定的软件子功能的族;
第二步,写一个驱动程序(用于测试的控制程序),协调测试数据的输入和输出;
第三步,对由模块组成的子功能族进行测试;
第四步,去掉驱动程序,沿软件结构自下向上移动,把子功能族组合起来形成更大的子功能族。
上述第二步到第四步实质上构成了一个循环。
7.4.2自底向上集成
自底向上结合
自底向上结合
7.4.3不同集成测试策略的比较
不同集成测试方法的比较:
方法
优点
缺点
非渐
增式
䦋㌌㏒㧀좈琰茞ᓀ㵂Ü
没有错误隔离手段
主要设计错误发现迟
潜在可重用代码测试不充分
需要驱动程序和存根程序
自顶
向下
具有错误隔离手段
主要设计错误发现早
不需要驱动程序
潜在可重用代码测试不充分
需要存根程序
自底
向上
具有错误隔离手段
潜在可重用代码能充分测试
不需要存根程序
主要设计错误发现迟
需要驱动程序
混合
具有错误隔离手段
主要设计错误发现早
潜在可重用代码能充分测试
䦋㌌㏒㧀좈琰茞ᓀ㵂Ü
混合策略:
改进的自顶向下测试方法
基本上使用自顶向下的测试方法,但是在早期使用自底向上的方法测试软件中的少数关键模块。
能在测试的早期发现关键模块中的错误;测试关键模块时需要驱动程序。
混合法
对软件结构中较上层使用的自顶向下方法与对软件结构中较下层使用的自底向上方法相结合。
兼有两种方法的优缺点,当被测试的软件中关键模块比较多时,这种混合法可能是最好的折衷方法。
7.4.4回归测试
回归测试是指重新执行已经做过的测试的某个子集,以保证测试过程中的变化没有带来非预期的副作用。
回归测试就是用于保证由于调试或其他原因引起的变化,不会导致非预期的软件行为或额外错误的测试活动。
回归测试可以通过重新执行全部测试用例的一个子集人工地进行,也可以使用自动化的捕获回放工具自动进行。
7.5确认测试
确认测试也称为验收测试,它的目标是验证软件的有效性。
软件有效性的一个简单定义是:
如果软件的功能和性能如同用户所合理期待的那样,软件就是有效的。
需求分析阶段产生的软件需求规格说明书,准确地描述了用户对软件的合理期望,因此是软件有效性的标准,也是进行确认测试的基础。
确认测试必须有用户积极参与,或者以用户为主进行。
使用用户界面输入测试数据并且分析评价测试的输出结果。
通常在验收之前由开发单位对用户进行培训。
7.5.1确认测试的范围
确认测试的一个重要内容是复查软件配置。
复查的目的是保证软件配置的所有成分都齐全,质量符合要求,文档与程序完全一致,具有完成软件维护所必须的细节,而且已经编好目录。
7.5.2软件配置复查
Alpha测试由用户在开发者的场所进行,并且在开发者对用户的“指导”下进行测试。
Alpha测试是在受控的环境中进行的。
Beta测试由软件的最终用户们在一个或多个客户场所进行。
开发者通常不在Beta测试的现场,因此,Beta测试是软件在开发者不能控制的环境中的“真实”应用。
7.5.3Alpha和Beta测试
测试阶段
主要依据
测试人员
测试方式
主要测试内容
单元测试
系统设计文档
开发小组
白盒测试
接口测试
路径测试
子系统
测试
系统设计文档
需求文档
独立测试
小组
白盒测试
黑盒测试
接口测试
路径测试
功能测试
性能测试
系统测试
需求文档
独立测试
小组
黑盒测试
功能测试
健壮性测试
性能测试
用户界面测试
安全性测试
压力测试
可靠性测试
安装/反安装测试
验收测试
需求文档
用户
黑盒测试
测试总结:
1.接口测试
每个接口可能有多个输入参数,每个参数有“典型值”、“边界值”、“异常值”之分。
根据接口的定义,可以推断某种输入应当产生什么样的输出。
输出包括函数的返回值和输出参数。
观察是否有程序语句从来没有被执行过。
要特别留意函数体内的错误处理程序块。
2.路径测试
想遍历测试几乎是不可能的,不测试或者胡乱找几条路径测试却又不行。
输入与对应的输出之间的路径是唯一的。
由于接口测试时的输入是有代表性的,因此相应的路径也具有代表性。
路径测试检查表:
数据类型、变量值、逻辑判断、循环、内存管理、文件I/O、错误处理。
3.功能测试
功能测试的基本方法是构造一些合理输入(在需求范围之内),检查输出是否与期望相同。
功能测试有两种比较好的测试方法:
等价划分法和边界值分析法。
等价划分是指把输入空间划分为几个“等价区间”,在每个“等价区间”中只需要测试一个典型值就可以了。
边界值测试法是对等价划分法的补充。
除了典型值外还要用边界值作为测试用例。
4.健壮性测试
健壮性是指在异常情况下,软件能正常运行的能力。
健壮性有两层含义:
容错能力。
容错性测试通常构造一些不合理的输入来引诱软件出错。
恢复能力。
恢复测试重点考察以下几项:
系统能否重新运行;
有无重要的数据丢失;
是否毁坏了其它相关的软件硬件。
5.性能测试
性能测试即测试软件处理事务的速度,一是为了检验性能是否符合需求,二是为了得到某些性能数据供人们参考。
有时人们关心测试的“绝对值”。
有时人们关心测试的“相对值”。
6.用户界面测试
绝大多数软件拥有图形用户界面。
图形用户界面的测试重点是正确性、易用性和视觉效果。
在评价易用性和视觉效果时,主观性非常强,应当考虑多个人的观点。
7.信息安全测试
信息安全性是指防止系统被非法入侵的能力,既属于技术问题又属于管理问题。
信息安全性测试有如下步骤:
为非法入侵设立目标;
邀请(或悬赏)一些人扮演黑客,让他们想尽办法入侵系统,实现“目标”。
如果有人成功了,请他详述入侵的过程。
8.压力测试
压力测试也叫负荷测试,即获取系统能正常运行的极限状态。
压力测试的主要任务是:
构造正确的输入,使劲折腾系统却让它刚好不瘫痪。
压力测试的一个变种是敏感测试。
敏感测试目的是发现什么样的输入可能会引发不稳定现象。
9.可靠性测试
可靠性是指在一定的环境下、给定的时间内、系统不发生故障的概率。
软件可靠性测试可能会花费很长时间。
比较实用的办法是,让用户使用该系统,记录每一次发生故障的时刻。
计算出相邻故障的时间间隔,注意要去掉非工作时间。
统计出不发生故障的“最小时间间隔”、“最大时间间隔”和“平均时间间隔”。
10.安装/反安装测试
目前市面上有非常流行的、专门制作安装/反安装程序的一些工具,如InstallShelled。
主要测试工作:
至少在标准配置和最低配置两种环境下测试;
如果有安装界面,应当尝试各种选项,如选择“全部”、“部分”、“升级”等。
7.6白盒测试技术
所谓测试方案包括具体的测试目的(例如,预定要测试的具体功能),应该输入的测试数据和预期的结果。
通常又把测试数据和预期的输出结果称为测试用例。
7.6.1逻辑覆盖
有选择地执行程序中某些最有代表性的通路是对穷尽测试的惟一可行的替代办法。
从覆盖源程序语句的详尽程度分析,大致有以下一些不同的覆盖标准:
语句覆盖
判定覆盖
条件覆盖
判定/条件覆盖
条件组合覆盖
1.语句覆盖
含义:
选择足够多的测试数据,使被测程序中每个语句至少执行一次。
分析:
执行路径sacbed
测试用例:
A=2,B=0,X=4
覆盖sacbed
语句覆盖特点:
语句覆盖对程序的逻辑覆盖很少。
语句覆盖只关心判定表达式的值,而没有分别测试判定表达式中每个条件取不同值时的情况。
语句覆盖是很弱的逻辑覆盖标准。
2.判定覆盖(分支覆盖)
含义:
不仅每个语句必须至少执行一次,而且每个判定的每种可能的结果都应该至少执行一次。
所有判定分支:
(1)a点判定为T
(2)a点判定为F
(3)b点判定为T
(4)b点判定为F
2.判定覆盖(分支覆盖)
测试用例:
Ⅰ.满足
(1)(4)
A=3,B=0,X=3
覆盖sacbd
Ⅱ.满足
(2)(3)
A=2,B=1,X=1
覆盖sabed
2.判定覆盖(分支覆盖)
或者
Ⅰ.满足
(1)(3)
A=2,B=0,X=3