1.3 通过维恩图理解测试
测试基本上关心的是行为,而行为与软件开发人员常用的结构视图无关。
结构视图关注的是它是什么,而行为视图关注的是它做什么。基本文档大多都是开发人员编写的,强调的是结构信息,而不是行为信息。
如上图所示:S:需求规格说明所描述的行为,P:程序实现的行为,U:全集,所有的程序行为。
- 所描述的行为没有实现,也就是S-P,图中的1,这就是遗漏缺陷;
- 已实现的行为没有描述或实现与描述不一致,也就是P-S,图中的2,这就是过错性缺陷;
- S和P相交的部分,也就是S∩P,图中的3,描述和实现一致,是“正确”部分,即既被描述又被实现的行为。
测试的一种很好的观点是,测试就是确定既被描述又被实现程序行为的范围。“正确性”只有在一个规格说明和一种实现背景下才有意义,正确性是一种相对术语,不是绝对术语。
分析S、P、T之间的关系。
- 没有测试的已描述行为:2、5
- 经过测试的已描述行为:1、4
- 未描述行为的测试用例:3、7
- 没有测试的程序行为:2、6
- 经过测试的程序行为:1、3
- 未实现行为的测试用例:4、7
这些区域中每一个都很重要
(1)如果测试用例没有覆盖已描述行为(2、5),则测试一定是不完备的。
(2)如果特定测试用例对应未描述行为(3、7),则有两种可能:要么这个测试用例是不正当的,要么规格说明是不充分的。
(3)如果测试用没有覆盖已实现的行为(2、6),测试是不完备的,6尽管未在需求规格中描述,但要通过测试确定是需求规格遗漏,还是不应该的实现。
(4)如果特定测试用例对应未实现的行为(4、7),也有两种可能:要么是这个测试用例是不适当的,要么是程序实现有遗漏。
一个优秀的测试工程师的目标:(1)通过努力使得这些集合都相交的区域1尽可能大。(2)采用合理适当的方法设计集合T。
1.4 标识测试用例
两种基本的测试用例标识方法:功能性测试和结构性测试。
本书讨论的问题只是软件测试类型中的功能测试的方法,未涉及到其它测试类型,比如:性能测试、接口测试、安装性测试、文档审查、代码审查等。这可理解这本书主要讨论的范围就是功能测试,功能测试在所有类型的测试中应该占据80%的比例,毕竟对于一个软件来说功能实现与否,实现的是否正确是第一重要的,当然其它要求,比如性能、接口、安装性等也很重要,其它类型的测试,将在后续的博客中进行讨论。
这里讨论的功能性测试和结构性测试应该都可归结为功能测试,一个是基于规格说明,或者说是黑盒测试,一个是基于程序结构的测试,或者说是白盒测试。
1.4.1 功能性测试
功能性测试的基本观点是,任何程序都可以看作是将从输入定义域取值映射到输出值域的函数。这种观点常常在工程中使用,将系统看作是黑盒。于是产生了术语黑盒测试,其中黑盒的内容或实现是不知道的,而用输入和输出表示的黑盒函数则被完全了解。这种方法是面向对象的核心。比如,大多数人可以成功地仅仅凭借黑盒知识来操作和驾驶汽车,而不需要知道关于发动机、离合器、传动装置等结构性知识。
采用功能性方法标识测试用例,所使用的唯一信息就是软件的规格说明。
功能性测试的两个优点:(1)功能性测试与软件如何实现无关,所以实现发生变化,测试用例依然有用;(2)测试用例开发可以与实现并行进行,可以压缩总的项目开发时间。
另外一个优点可能是,能够发现遗漏性缺陷,比如韦恩图中的4。
缺点:(1)测试用例之间可能存在严重的冗余;(2)还可能有未测试的软件漏洞。
这里的一个关键,就是软件需求规格说明要足够的准确,这在很多的实际项目中是很难做到的,关键还是看项目组的文化和共事方式,需求分析人员、设计人员、开发人员和测试人员之间通过什么来交互,好的文化和架构当然是一份可以大家都能够达成共识的没有歧义的规格说明。
对于第三方测试,或者没有一个共同标准遵循的组织,不同的角色和人员对同一个问题没有一个共同的认识,将会造成无尽的麻烦,这也许是造成很多测试不能充分进行的重要根源之一,遇到这种情况,可能需要相关涉众能够耐心的坐下来,认真的进行沟通,但沟通的代价和效果可能会大打折扣。
第二部分将讨论功能性测试的主流方法,包括(1)边界值分析、(2)健壮性分析、(3)最坏情况分析、(4)等价类分析和(5)决策表分析等。这些手段或方法的共同特征是,都基于被测软件的定义信息。其数学背景知识是离散数学。
不同的方法标识测试用例的能力可能不同,没有最好,只有更合适,也就是说根据实际的软件特点和问题,选择合适的一种或几种方法来设计和标识测试用例。
功能性测试回答的问题:有没有实现对,是否做对了,是否是需求想要的,盖了一个三层的楼,是用户的需求,该有的房间、功能区域都有,但不知道房子用的是什么材料,墙体里面是什么,这种结构和设计方式是否结实,可靠,可能心里没有底。
功能性测试用例标识方法比较
1.4.2 结构性测试
结构性测试是另一种用于标识测试用例的基本方法,结构性测试有时叫做白盒测试。“看到黑盒内部”的能力,使测试人员能够根据功能实际实现的方式来标识测试用例。
对于结构性测试,或者说白盒测试的使用,有时是必须的,有时测试人员是回避的,因为理解实现的结构和阅读代码的难度,往往是横在测试工程师面前的一个鸿沟,另外一个是时间和开发人员的配合问题,对于一个项目的内部测试还好,对于第三方测试,还有所谓的知识产权问题,这些都不应该成为回避白盒测试的充分理由,还有测试阶段问题,对于处于验收阶段的系统测试,或验收测试,再去进行结构性测试可能有些难度,花费的时间和人力会比较多。不论怎样,软件测试理论上起源于结构性测试,行业前期的很多研究也是基于结构性测试的,这个是基础,可以是一个很好的借鉴。可以借用结构性测试的方法,来开展系统测试,就像第14章系统测试中使用的有限状态机一样,和程序的控制流相似。
结构性测试一直是一些相当强的理论的主题。为了真正理解结构性测试,熟悉先行图论的概念是很关键的。通过这些概念,测试人员可以严格描述要测试的确切内容。由于具有很强的图论基础,结构性测试本身又引出测试覆盖指标的定义和使用。测试覆盖指标提供明确的描述软件项测试范围的方法,而这又使测试管理变得有意义。
结构性测试回答的问题:实现是否正确,做了的是否对,与是否是用户或需求想要的不一定有直接关系,比如本来想要的是一个三个轮子的车,结果做出了一个四个轮子的车,做的还挺好,本来需要盖一个三层的楼,实际盖了一个二层的楼,房屋质量都正确,也挺结实,但没有实现需求。
另外,基于程序的实现,比如菜单结构,界面要素等进行测试用例设计不知道是否应该也属于结构性测试的类别。
结构性测试用例标识方法的比较
1.4.3 功能性测试与结构性测试的比较
如果读者阅读过很多文献,就会发现两种方法都有坚定的拥护者。对于结构性测试,Robert Poston写到:“这种工具自20世纪70年代以来一直在浪费测试人员的时间,……[它]不支持好的软件测试实践,应该从测试人员的工具包中剔除”;Edward Miller在为结构性测试辩护时写到:“如果达到85%或更好的水平,分支覆盖标识出的缺陷,一般是靠功能性测试找出缺陷的两倍”。
功能性测试只利用规格说明标识测试用例,而结构性测试使用程序源代码(实现)作为测试用例标识的基础。两种方法单独使用各有优缺点,单独使用都是不充分的,两种方法都需要,只是如何在实践中相互配合使用,明智的组合会带来功能性的置信(软件完成需求的能力),以及结构性测试的度量(测试了软件的多少)
在自己的实践中,主要是功能性测试站了绝大部分,比较纠结的事情是大部分的项目的需求规格说明并未能描述出软件的所有行为和结构,从中并不能直接到处有价值的测试项和测试用例,主要还要依靠软件的实现和对软件实现的业务本身的理解和认识来生成测试用例和测试项,正因为如此,软件测试其实并不是一件像理论上看似那么简单的工作,需要掌握更多的能看到的信息背后的内容,知道哪些是重要的,哪些地方可能更容易产生错误。实际上软件功能测试是一项智力活动,测试用例设计有时候就如同算法设计一样,使用常规方法能够产生一些测试用例,但每个测试人员对于同一个问题会设计出不同的测试用例,如何设计出既少有满足充分性要求的测试用例是一项要求很高的任务,也许这就是这本书所说的Craftsman。
1.5 错误和缺陷分类
有多种方法可以对缺陷分类:以出现相应错误的开发阶段来划分,以相应失效产生的后果来划分,以解决难度来划分,以不解决会产生的风险来划分。作者更喜欢根据异常的出现频率来划分:只出现一次、间歇出现、反复出现、可重复出现。
Beizer给出的一种缺陷分类
软件异常IEEE标准分类(IEEE,1993)定义了围绕4个阶段构建的详细异常解决过程:识别、调查、行动和处置。下面是作者结合IEEE给出的一些异常(缺陷)分类。
1.6 测试级别
对应于瀑布模型的需求分析、概要设计和详细设计三个部分,相应的有三个级别的测试,分别为单元测试、集成测试与系统测试,对应关系如图所示。
测试级别与功能性和结构性测试存在现实的关系。大多数实践者都同意结构性测试最适合在单元级别上进行,而功能性测试最适合在系统级别上进行。这在一般情况下是正确的,结构性测试也可用在集成测试和系统测试级别上。关于测试级别问题,将会在合适的时机进行一个专门的讨论。
PS:刚刚开始写一些东西,使用这个编辑器还比较费劲,后面先学习一下MarkDown编辑器用法,不知道会不会好点,另外Word里面也带了一个博客编辑方式,不知道能不能用在这里,先试一下吧。文中的图表都是截图。