黑盒测试案例设计技术篇
1 概述
本章介绍黑盒测试的概念和进行黑盒测试的目的与意义,及关于等价类划分、边界值分析、因果图法、判定表法、正交试验法、功能图法等测试用例设计方法的原理与实现,并从测试设计说明、测试用例说明、测试程序说明三个方面介绍如何编写测试用例,最后结合一个ATM的例子体现如何设计测试用例。
2 测试用例设计方法
初涉软件测试者可能认为拿到软件后就可以立即进行测试,并希望马上找出软件的所有缺陷,这种想法就如同没有受过工程训练的开发工程师急于去编写代码一样。软件测试也是一个工程,也需要按照工程的角度去认识软件测试,在具体的测试实施之前,我们需要明白我们测试什么,怎么测试等,也就是说通
过制定测试用例指导测试的实施。
2.1 什么是测试用例
所谓的测试用例设计就是将软件测试的行为活动,作一个科学化的组织归纳。软件测试是有组织性、步骤性和计划性的,而设计软件测试用例的目的,就是为了能将软件测试的行为转换为可管理的模式。软件测试是软件质量管理中最实际的行动,同时也是耗时最多的一项。基于时间因素的考虑,软件测试行为必须能够加以量化,才能进一步让管理阶层掌握所需要的测试过程,而测试用例就是将测试行为具体量化的方法之一。
简单地说,测试用例就是设计一个情况,软件程序在这种情况下,必须能够正常运行并且达到程序所设计的执行结果。如果程序在这种情况下不能正常运行,而且这种问题会重复发生,那就表示软件程序人员已经测出软件有缺陷,这时候就必须将这个问题标示出来,并且输入到问题跟踪系统内,通知软件开发人员。软件开发人员接获通知后,将这个问题修改完成于下一个测试版本内,软件测试工程师取得新的测试版本后,必须利用同一个用例来测试这个问题,确保该问题已修改完成。
因为我们不可能进行穷举测试,为了节省时间和资源、提高测试效率,必须要从数量极大的可用测试数据中精心挑选出具有代表性或特殊性的测试数据来进行测试。
使用测试用例的好处主要体现在以下几个方面。
① 在开始实施测试之前设计好测试用例,可以避免盲目测试并提高测试效率。
② 测试用例的使用令软件测试的实施重点突出、目的明确。
③ 在软件版本更新后只需修正少部分的测试用例便可展开测试工作,降低工作强度,缩短项目周期。
④ 功能模块的通用化和复用化使软件易于开发,而测试用例的通用化和复用化则会使软件测试易于开展,并随着测试用例的不断精化其效率也不断攀升。
具体的黑盒测试用例设计方法包括等价类划分法、边界值分析法、错误推测法、因果图法、判定表驱动法、正交试验设计法、功能图法等。应该说,这些方法是比较实用的,但采用什么方法,在使用时自然要针对开发项目的特点对方法加以适当的选择。下面我们讨论几种常用的方法。
2.2 等价类划分法
等价类划分是一种典型的黑盒测试方法,用这一方法设计测试用例完全不考虑程序的内部结构,只根据对程序的要求和说明,即需求规格说明书。我们必须仔细分析和推敲说明书的各项需求,特别是功能需求。把说明中对输入的要求和输出的要求区别开来并加以分解。
由于穷举测试工作量太大,以至于无法实际完成,促使我们在大量的可能数据中选取其中的一部分作为测试用例。例如,在不了解等价分配技术的前提下,我们做计算器程序的加法测试时,测试了1 1,1 2,1 3和1 4之后,还有必要测试1 5和1 6吗,能否放心地认为它们是正确的?我们感觉1 5和1 6,与前面的1 1,1 2都是很类似的简单加法。
等价类划分的办法是把程序的输入域划分成若干部分,然后从每个部分中选取少数代表性数据作为测试用例。每一类的代表性数据在测试中的作用等价于这一类中的其他值,也就是说,如果某一类中的一个例子发现了错误,这一等价类中的其他例子也能发现同样的错误;反之,如果某一类中的一个例子没有发现错误,则这一类中的其他例子也不会查出错误(除非等价类中的某些例子属于另一等价类,因为几个等价类是可能相交的)。使用这一方法设计测试用例,首先必须在分析需求规格说明的基础上划分等价类,列出等价类表。
1.划分等价类和列出等价类表
等价类是指某个输入域的子集合。在该子集合中,各个输入数据对于揭露程序中的错误都是等效的。并合理地假定:测试某等价类的代表值就等于对这一类其他值的测试。
因此,可以把全部输入数据合理地划分为若干等价类,在每一个等价类中取一个数据作为测试的输入条件,就可以用少量代表性的测试数据取得较好的测试结果。等价类划分有两种不同的情况:有效等价类和无效等价类。
有效等价类:指对于程序的规格说明来说是合理的、有意义的输入数据构成的集合。利用有效等价类可检验程序是否实现了规格说明中所规定的功能和性能。
无效等价类:与有效等价类的定义恰巧相反。
设计测试用例时,要同时考虑这两种等价类。因为软件不仅要能接收合理的数据,也要能经受意外的考验。这样的测试才能确保软件具有更高的可靠性。
下面给出6条确定等价类的原则:
① 在输入条件规定了取值范围或值的个数的情况下,可以确立一个有效等价类和两个无效等价类。
② 在输入条件规定了输入值的集合或者规定了“必须如何”的条件的情况下,可以确立一个有效等价类和一个无效等价类。
③ 在输入条件是一个布尔量的情况下,可确定一个有效等价类和一个无效等价类。
④ 在规定了输入数据的一组值(假定n个),并且程序要对每一个输入值分别处理的情况下,可确立n个有效等价类和一个无效等价类。
⑤ 在规定了输入数据必须遵守的规则的情况下,可确立一个有效等价类(符合规则)和若干个无效等价类(从不同角度违反规则)。
⑥ 在确知已划分的等价类中,各元素在程序处理中的方式不同的情况下,则应再将该等价类进一步地划分为更小的等价类。
在确立了等价类之后,建立等价类表,列出所有划分出的等价类如表5-1所示。
表5-1 等价类表示例
输入条件 | 有效等价类 | 无效等价类 | 输入条件 | 有效等价类 | 无效等价类 |
… | … | … | … | … | … |
2.确定测试用例
根据已列出的等价类表,按以下步骤确定测试用例:
① 为每个等价类规定一个惟一的编号。
② 设计一个新的测试用例,使其尽可能多地覆盖尚未覆盖的有效等价类。重复这一步,最后使得所有有效等价类均被测试用例所覆盖。
③ 设计一个新的测试用例,使其只覆盖一个无效等价类。重复这一步使所有无效等价类均被覆盖。
在寻找等价区间时,想办法把软件的相似输入、输出、操作分成组。这些组就是等价区间。请看一些例子。
在两数相加用例中,测试1 13和1 99999999似乎有点不同。这是一种直觉,一个是普通加法,而另一个似乎有些特殊,这个直觉是对的。程序对1和最大数值相加的处理和对两个小一些的数值相加的处理有所不同。后者必须处理溢出情况。因为软件操作可能不同,所以这两个用例属于不同的等价区间。
如果具有编程经验,就可能会想到更多可能导致软件操作不同的“特殊”数值。如果不是程序员,也不用担心,你很快就会学到这种技术,无须了解代码细节就可以运用。
如图5-1
如图5-1所示是复制的多种方法,给出了选中编辑菜单后显示复制和粘贴命令的计算器程序。每一项功能(即复制和粘贴)有5种执行方式。要想复制,可以单击复制菜单命令,键入C,按Ctrl C或Ctrl Shift C组合键。任何一种输入途径都会把当前数值复制到剪贴板中,一一执行同样的输出操作,产生同样的结果。
如果要测试复制命令,可以把这5种输入途径划分减为3个,单击菜单命令,键入C和按Ctrl C组合键。对软件质量有了信心之后,知道无论以何种方式激活复制功能都工作正常,甚至可以进一步缩减为1个区间,例如按Ctrl C组合键。
再看下一个例子。看一下在标准的另存为对话框(如图5-2所示)中输入文件名称的情形。
Windows文件名可以包含除了“、”、“/”、“:”、“·”、“?”、“<>”和“”之外的任意字符。文件名长度是1~255个字符。如果为文件名创建测试用例,等价区间有合法字符、非法字符、合法长度的名称、过长名称和过短名称。
例题:根据下面给出的规格说明,利用等价类划分的方法,给出足够的测试用例。“一个程序读入3个整数,把这3个数值看作一个三角形的3条边的长度值。这个程序要打印出信息,说明这个三角形是不等边的、是等腰的、还是等边的”。
我们可以设三角形的3条边分别为A,B,C。如果它们能够构成三角形的3条边,必须满足:
A>0,B>0,C>0,且A B>C,B C>A,A C>B。
图5-2 存盘对话框
如果是等腰的,还要判断A=B,或B=C,或A=C。
如果是等边的,则需判断是否A=B,且B=C,且A=C。
列出等价类表,如表5-2所示。
表5-2 等 价 类 表
输 入 条 件 | 有效等价类 | 无效等价类 |
是否三角形的3条边 | (A>0), (1) (B>0), (2) (C>0), (3) (A B>C), (4) (B C>A), (5) (A C>B) (6) | (A≤0), (7) (B≤0), (8) (C≤0), (9) (A B≤C), (10) (B C≤A), (11) (A C≤B) (12) |
是否等腰三角形 | (A=B), (13) (B=C), (14) (C=A), (15) | (A≠B)and(B≠C)and(C≠A), (16) |
是否等边三角形 | (A=B)and(B=C)and(C=A), (17) | (A≠B), (18) (B≠C), (19) (C≠A), (20) |
设计测试用例:输入顺序是【A,B,C】,如表5-3所示。
表5-3 测 试 用 例
序号 | 【A,B,C】 | 覆盖等价类 | 输 出 |
1 | 【3,4,5】 | (1),(2),(3),(4),(5),(6) | 一般三角形 |
2 | 【0,1,2】 | (7) | 不能构成三角形 |
3 | 【1,0,2】 | (8) | |
4 | 【1,2,0】 | (9) | |
5 | 【1,2,3】 | (10) | |
6 | 【1,3,2】 | (11) | |
7 | 【3,1,2】 | (12) | |
8 | 【3,3,4】 | (1),(2),(3),(4),(5),(6),(13) | 等腰三角形 |
9 | 【3,4,4】 | (1),(2),(3),(4),(5),(6),(14) | |
10 | 【3,4,3】 | (1),(2),(3),(4),(5),(6),(15) | |
11 | 【3,4,5】 | (1),(2),(3),(4),(5),(6),(16) | 非等腰三角形 |
12 | 【3,3,3】 | (1),(2),(3),(4),(5),(6),(17) | 是等边三角形 |
13 | 【3,4,4】 | (1),(2),(3),(4),(5),(6),(14),(18) | 非等边三角形 |
14 | 【3,4,3】 | (1),(2),(3),(4),(5),(6),(15),(19) | |
15 | 【3,3,4】 | (1),(2),(3),(4),(5),(6),(13),(20) |
请记住,等价分配的目标是把可能的测试用例组合缩减到仍然足以满足软件测试需求为止。因为,选择了不完全测试,就要冒一定的风险,所以必须仔细选择分类。
关于等价分配最后要讲的一点是,这样做有可能不客观。科学有时也是一门艺术。测试同一个复杂程序的两个软件测试员,可能会制定出两组不同的等价区间。只要审查等价区间的人都认为它们足以覆盖测试对象就可以了。
2.3 边界值分析法
人们从长期的测试工作经验得知,大量的错误是发生在输入或输出范围的边界上的,而不是在输入范围的内部。因此针对各种边界情况设计测试用例,可以查出更多的错误。例如,在做三角形计算时,要输入三角形的3个边长A、B和C。这3个数值应当满足A>0、B>0、C>0、A B>C、A C>B、B C>A,才能构成三角形。但如果把6个不等式中的任何一个大于号“>”错写成大于等于号“≥”,那就不能构成三角形。问题恰恰出现在容易被疏忽的边界附近。这里所说的边界是指相当于输入等价类和输出等价类而言,稍高于其边界值及稍低于其边界值的一些特定情况。
1.边界条件
我们可以想象一下,如果在悬崖峭壁边可以自信地安全行走,平地就不在话下了。如果软件在能力达到极限时能够运行,那么在正常情况下一般也就不会有什么问题。
边界条件是特殊情况,因为编程从根本上说不怀疑边界有问题。奇怪的是,程序在处理大量中间数值时都是对的,但是可能在边界处出现错误。下面的一段源代码说明了在一个极简单的程序中是如何产生边界条件问题的。
rem create a 10 element integer array
rem initialize each element to–1
dim data(10)as integer
dim i as integer
for i=1 to 10
data(i)=–1
next i
end
这段代码的意图是创建包含10个元素的数组,并为数组中的每一个元素赋初值–1。看起来相当简单。它建立了包含10个整数的数组data和一个计数值i。For循环是从1~10,数组中从第1个元素到第10个元素被赋予数值–1。那么边界问题在哪儿呢?
在大多数开发语言脚本中,应当以声明的范围定义数组,在本例中定义语句是dim data(10)as interger,第一个创建的元素是data(0),而不是data(1)。该程序实际上创建了一个从data(0)~ data(10)共11个元素的数组。程序从1~10循环将数组元素的值初始化为-1,但是由于数组的第一个元素是data(0),因此它没有被初始化。程序执行完毕,数组值如下:
data(0)= 0data(6)= –1
data(1)= –1data(7)= –1
data(2)= –1data(8)= –1
data(3)= –1data(9)= –1
data(4)= –1data(10)= –1
data(5)= –1
注意data(0)的值是0,而不是–1。如果这位程序员以后忘记了,或者其他程序员不知道这个数据数组是如何初始化的,那么他就可能会用到数组的第1个元素data(0),以为它的值是–1。诸如此类的问题很常见,在复杂的大型软件中,可能导致极其严重的软件缺陷。
2.次边界条件
上面讨论的普通边界条件是最容易找到的。它们在产品说明书中有定义,或者在使用软件的过程中确定。而有些边界在软件内部,最终用户几乎看不到,但是软件测试仍有必要检查。这样的边界条件称为次边界条件或者内部边界条件。
寻找这样的边界不要求软件测试员具有程序员那样阅读源代码的能力,但是要求大体了解软件的工作方式。2的乘方和ASCII表就是这样的例子。
(1)2的乘方
计算机和软件的计数基础是二进制数,用位(bit)来表示0和1,一个字节(byte)由8位组成,一个字(word)由两个字节组成等。表5-4中列出了常用的2的乘方单位及其范围或值。
表5-4 软件中2的乘方
术 语 | 范围或值 | 术 语 | 范围或值 |
位 | 0或1 | 千 | 1,024 |
双位 | 0~15 | 兆 | 1,048,576 |
字节 | 0~255 | 亿 | 1,073,741,824 |
字 | 0~65,535 | 万亿 | 1,099,511,627,776 |
表5-4中所列的范围和值是作为边界条件的重要数据。除非软件向用户提出这些范围,否则在需求文档中不会指明。然而,它们通常由软件内部使用,外部是看不见的,当然,在产生软件缺陷的情况下可能会看到。
在建立等价区间时,要考虑是否需要包含2的乘方边界条件。例如,如果软件接受用户输入1~1000范围内的数字,谁都知道在合法区间中包含1和1000,也许还要有2和999。为了覆盖任何可能的2的乘方次边界,还要包含临近双位边界的14、15和16,以及临近字节边界的254、255和256。
(2)ASCII表
另一个常见的次边界条件是ASCII字符表。如表5-5所示是部分ASCII值表的清单。
表5-5 部分ASCII值表
字符 | ASCII值 | 字符 | ASCII值 | 字符 | ASCII值 | 字符 | ASCII值 |
Null | 0 | B | 66 | 2 | 50 | a | 97 |
Space | 32 | Y | 89 | 9 | 57 | b | 98 |
/ | 47 | Z | 90 | : | 58 | y | 121 |
0 | 48 | [ | 91 | @ | 64 | z | 122 |
1 | 49 | ' | 96 | A | 65 | { | 123 |
注意,表5-5不是结构良好的连续表。0~9的后面ASCII值是48~57。斜杠字符(/)在数字0的前面,而冒号字符“:”在数字9的后面。大写字母A~Z对应65~90。小写字母对应97~122。这些情况都代表次边界条件。
如果测试进行文本输入或文本转换的软件,在定义数据区间包含哪些值时,参考一下ASCII表是相当明智的。例如,如果测试的文本框只接受用户输入字符A~Z和a~z,就应该在非法区间中包含ASCII表中这些字符前后的值@、[ 、和{ 。
(3)其他一些边界条件
另一种看起来很明显的软件缺陷来源是当软件要求输入时(比如在文本框中),不是没有输入正确的信息,而是根本没有输入任何内容,只按了Enter键。这种情况在产品说明书中常常被忽视,程序员也可能经常遗忘,但是在实际使用中却时有发生。程序员总会习惯性地认为用户要么输入信息,不管是看起来合法的或非法的信息,要么就会选择Cancel键放弃输入,如果没有对空值进行好的处理的话,恐怕程序员自己都不知道程序会引向何方。
正确的软件通常应该将输入内容默认为合法边界内的最小值,或者合法区间内的某个合理值,否则,返回错误提示信息。
因为这些值通常在软件中进行特殊处理,所以不要把它们与合法情况和非法情况混在一起,而要建立单独的等价区间。
3.边界值的选择方法
边界值分析是一种补充等价划分的测试用例设计技术,它不是选择等价类的任意元素,而是选择等价类边界的测试用例。实践证明,为检验边界附近的处理专门设计测试用例,常常取得良好的测试效果。边界值分析法不仅重视输入条件边界,而且也适用于输出域测试用例。
对边界值设计测试用例,应遵循以下几条原则:
① 如果输入条件规定了值的范围,则应取刚达到这个范围的边界的值,以及刚刚超越这个范围边界的值作为测试输入数据。
② 如果输入条件规定了值的个数,则用最大个数、最小个数、比最小个数少1、比最大个数多1的数作为测试数据。
③ 根据规格说明的每个输出条件,使用前面的原则①。
④ 根据规格说明的每个输出条件,应用前面的原则②。
⑤ 如果程序的规格说明给出的输入域或输出域是有序集合,则应选取集合的第一个元素和最后一个元素作为测试用例。
⑥ 如果程序中使用了一个内部数据结构,则应当选择这个内部数据结构边界上的值作为测试用例。
⑦ 分析规格说明,找出其他可能的边界条件。
2.4 错误推测法
错误推测法就是基于经验和直觉推测程序中所有可能存在的各种错误,有针对性地设计测试用例的方法。
错误推测法的基本思想是列举出程序中所有可能有的错误和容易发生错误的特殊情况,根据它们选择测试用例。例如,设计一些非法、错误、不正确和垃圾数据进行输入测试是很有意义的。如果软件要求输入数字,就输入字母。如果软件只接受正数,就输入负数。如果软件对时间敏感,就看它在公元3000年是否还能正常工作。还有,例如,在单元测试时曾列出的许多在模块中常见的错误,以前产品测试中曾经发现的错误等,这些就是经验的总结。另外,输入数据和输出数据为0的情况,或者输入表格为空格或输入表格只有一行,这些都是容易发生错误的情况。可选择这些情况下的例子作为测试用例。
2.5 因果图法
前节介绍的等价类划分方法和边界值分析法都是着重考虑输入条件,并没有考虑到输入情况的各种组合,也没考虑到各个输入情况之间的相互制约关系。如果在测试时必须考虑输入条件的各种组合,可能的组合数将是天文数字。因此必须考虑描述多种条件的组合,相应地产生多个动作的形式来考虑设计测试用例,这就需要利用因果图。在软件工程中,有些程序的功能可以用判定表的形式来表示,并根据输入条件的组合情况规定相应的操作。很自然,应该为判定表中的每一列设计一个测试用例,以便保证测试程序在输入条件的某种组合下,操作是正确的。
1.因果图设计方法
因果图法是从用自然语言书写的程序规格说明的描述中找出因(输入条件)和果(输出或程序状态的改变),通过因果图转换为判定表。
利用因果图导出测试用例需要经过以下几个步骤:
① 分析程序规格说明的描述中,哪些是原因,哪些是结果。原因常常是输入条件或是输入条件的等价类,而结果是输出条件。
② 分析程序规格说明的描述中语义的内容,并将其表示成连接各个原因与各个结果的“因果图”。
③ 标明约束条件。由于语法或环境的限制,有些原因和结果的组合情况是不可能出现的。为表明这些特定的情况,在因果图上使用若干个标准的符号标明约束条件。
④ 把因果图转换成判定表。
⑤ 为判定表中每一列表示的情况设计测试用例。
因果图生成的测试用例(局部,组合关系下的)包括了所有输入数据的取TRUE与取FALSE的情况,构成的测试用例数目达到最少,且测试用例数目随输入数据数目的增加而增加。
事实上,在较为复杂的问题中,这个方法常常是十分有效的,它能有力地帮助我们确定测试用例。当然,如果哪个开发项目在设计阶段就采用了判定表,也就不必再画因果图了,而是可以直接利用判定表设计测试用例了。
通常在因果图中,用Ci表示原因,Ei表示结果,其基本符号如图5-3所示。各结点表示状态,可取“0”或“1”值。“0”表示某状态不出现,“1”表示某状态出现。