软件测试基础教程杜文洁 景秀丽 主编中国水利水电出版社第八章 面向对象的软件测试本章概要:
本章通过面向对象软件开发的特点引入了面向对象的软件测试,通过传统软件测试和面向对象软件测试的比较,分析了面向对象软件测试是软件测试行业发展的必然方向。进而又详细描述了面向对象软件测试的方法和策略。最后较为详细的阐述了类测试的概念和方法。
第八章 面向对象的软件测试
8.1 面向对象软件测试的基本概念
8.2 面向对象测试的内容与范围
8.3 面向对象软件测试技术与方法
8.4 面向对象软件测试用例设计
8.5 面向对象测试基本步骤
8.6 面向对象测试工具 JUnit
第八章 面向对象的软件测试
8.1 面向对象软件测试的基本概念面向对象方法( Object-Oriented Method)是一种把面向对象的思想应用于 软件开发 过程中,指导开发活动的系统方法,是建立在“对象”概念基础上的方法学。面向对象方法作为一种新型的独具优越性的新方法正在逐渐代替被广泛使用的面向过程开发方法,被看成是解决软件危机的新兴技术。面向对象技术产生更好的系统结构,更规范的编程风格,极大的优化了数据使用的安全性,提高了程序代码的重用,一些人就此认为面向对象技术开发出的程序无需进行测试。
第八章 面向对象的软件测试
8.1 面向对象软件测试的基本概念
8.1.1 面向对象软件设计的基本概念
8.1.2 面向对象软件开发过程及其特点
8.1.3 向对象软件测试的基本概念第八章 面向对象的软件测试
8.1.1 面向对象软件设计的基本概念
1.对象对象是要研究的任何事物。从一本书到一家图书馆,单的整数到整数列庞大的数据库、极其复杂的自动化工厂、航天飞机都可看作对象,
它不仅能表示有形的实体,也能表示无形的(抽象的)规则、计划或事件。对象由数据(描述事物的属性)和作用于数据的操作(体现事物的行为)构成一独立整体。从程序设计者来看,对象是一个程序模块,从用户来看,对象为他们提供所希望的行为。在对内的操作通常称为方法。
2.类类是对象的模板。即类是对一组有相同数据和相同操作的对象的定义,
一个类所包含的方法和数据描述一组对象的共同属性和行为。类是在对象之上的抽象,对象则是类的具体化,是类的实例。类可有其子类,
也可有其它类,形成类层次结构。
3.消息消息是对象之间进行通信的一种规格说明。一般它由三部分组成:接收消息的对象、消息名及实际变元。
第八章 面向对象的软件测试
8.1.1 面向对象软件设计的基本概念
4.封装性封装是一种信息隐蔽技术,它体现于类的说明,是对象的重要特性。封装使数据和加工该数据的方法(函数)封装为一个整体,以实现独立性很强的模块,使得用户只能见到对象的外特性(对象能接受哪些消息,具有那些处理能力),而对象的内特性
(保存内部状态的私有数据和实现加工能力的算法)对用户是隐蔽的。封装的目的在于把对象的设计者和对象者的使用分开,使用者不必知晓行为实现的细节,只须用设计者提供的消息来访问该对象。
5.继承性继承性是子类自动共享父类之间数据和方法的机制。它由类的派生功能体现。一个类直接继职其它类的全部描述,同时可修改和扩充。
6.多态性对象根据所接收的消息而做出动作。同一消息为不同的对象接受时可产生完全不同的行动,这种现象称为多态性。利用多态性用户可发送一个通用的信息,而将所有的实现细节都留给接受消息的对象自行决定,如是,同一消息即可调用不同的方法。例如:
Print消息被发送给一图或表时调用的打印方法与将同样的 Print消息发送给一正文文件而调用的打印方法会完全不同。多态性的实现受到继承性的支持,利用类继承的层次关系,把具有通用功能的协议存放在类层次中尽可能高的地方,而将实现这一功能的不同方法臵于较低层次,这样,在这些低层次上生成的对象就能给通用消息以不同的响应。在 OOPL中可通过在派生类中重定义基类函数(定义为重载函数或虚函数)来实现多态性。
第八章 面向对象的软件测试
8.1.2 面向对象软件开发过程及其特点面向对象的开发方法的基本思想认为,客观世界是由各种各样的对象组成的,每种对象都有各自的内部状态和运动规律,不同的对象之间的相互作用和联系就构成了各种不同的系统。故面向对象软件开发的工作过程为:
1.调查、分析系统需求,建立一个全面、合理、统一的模型。
2.在繁杂的问题域中抽象地识别出对象以及其行为、结构、属性、方法
3.对象设计 —— 即对分析的结果作进一步地抽象、归类、
整理,并最终以范式的形式将它们确定下来。
4.程序实现 —— 即用面向对象的程序设计语言将上一步整理的范式直接映射(直接用程序语言来取代)为应用程序软件。
第八章 面向对象的软件测试
8.1.2 面向对象软件开发过程及其特点面向对象开发的特点是遵循以下三项原则:
1.抽象原则( abstraction) —— 指为了某一分析目的而集中精力研究对象的某一性质,它可以忽略其它与此目的无关的部分
2.封装原则( encapsulation)即信息隐藏 ——
指在确定系统的某一部分内容时,应考虑到其它部分的信息及联系都在这一部分的内部进行,外部各部分之间的信息联系应尽可能的少。
3.继承原则( inheritance) —— 指能直接获得已有的性质和特征而不必重复定义它们。
第八章 面向对象的软件测试
8.1.3 向对象软件测试的基本概念
1,什么是面向对象的软件测试面向对象程序的结构不再是传统的功能模块结构,
作为一个整体,原有集成测试所要求的逐步将开发的模块搭建在一起进行测试的方法已成为不可能。而且,面向对象软件抛弃了传统的开发模式,
对每个开发阶段都有不同以往的要求和结果,已经不可能用功能细化的观点来检测面向对象分析和设计的结果。因此,传统的测试模型对面向对象软件已经不再适用。针对面向对象软件的开发特点,应该有一种新的测试模型。
第八章 面向对象的软件测试
8.1.3 向对象软件测试的基本概念
2.面向对象测试与传统测试的区别传统测试模式与面向对象的测试模式的最主要的区别在于,面向对象的测试更关注对象而不是完成输入 /输出的单一功能,这样的话测试可以在分析与设计阶段就先行介入,便得测试更好的配合软件生产过程并为之服务。与传统测试模式相比,面向对象测试的优点在于:更早地定义出测试用例;早期介入可以降低成本;尽早的编写系统测试用例以便于开发人员与测试人员对系统需求的理解保持一致;面向对象的测试模式更注重于软件的实质。具体有如下不同:
( 1)测试的对象不同:传统软件测试的对象是面向过程的软件,一般用结构化方法构建;面向对象测试的对象是面向对象软件,采用面向对象的概念和原则,用面向对象的方法构建。
( 2)测试的基本单位不同:前者是模块;面向对象测试的基本单元是类和对象。
( 3)测试的方法和策略不同:传统软件测试采用白盒测试,黑盒测试,路径覆盖等方法;面向对象测试不仅吸纳了传统测试方法,也采用各种类测试等方法,而且集成测试和系统测试的方法和策略也很不相同。
第八章 面向对象的软件测试
8.1.3 向对象软件测试的基本概念
3.面向对象测试模型 (Object-Orient Test Model)
现代的软件开发工程是将整个软件开发过程明确的划分为几个阶段,将复杂问题具体按阶段加以解决。这样,在软件的整个开发过程中,可以对每一阶段提出若干明确的监控点,作为各阶段目标实现的检验标准,从而提高开发过程的可见度和保证开发过程的正确性。实践证明软件的质量不仅是体现在程序的正确性上,它和编码以前所做的需求分析,软件设计也密切相关。这时,对错误的纠正往往不能通过可能会诱发更多错误的简单的修修补补,而必须追溯到软件开发的最初阶段。因此,为了保证软件的质量,
应该着眼于整个软件生存期,特别是着眼于编码以前的各开发阶段的工作。于是,软件测试的概念和实施范围必须扩充,应该包括在整个开发各阶段的复查、评估和检测。
由此,广义的软件测试实际是由确认、验证、测试三个方面组成。
第八章 面向对象的软件测试
8.1.3 向对象软件测试的基本概念确认:是评估将要开发的软件产品是否是正确无误、可行和有价值的。比如,将要开发的软件是否会满足用户提出的要求,是否能在将来的实际使用环境中正确稳定的运行,是否存在隐患等。这里包含了对用户需求满足程度的评价。确认意味着确保一个待开发软件是正确无误的,是对软件开发构想的检测。
验证:是检测软件开发的每个阶段、每个步骤的结果是否正确无误,
是否与软件开发各阶段的要求或期望的结果相一致。验证意味着确保软件是会正确无误的实现软件的需求,开发过程是沿着正确的方向在进行。
测试:与狭隘的测试概念统一。通常是经过单元测试、集成测试、系统测试三个环节。
在整个软件生存期,确认、验证、测试分别有其侧重的阶段。确认主要体现在计划阶段、需求分析阶段、也会出现在测试阶段;验证主要体现在设计阶段和编码阶段;测试主要体现在编码阶段和测试阶段。
事实上,确认、验证、测试是相辅相成的。确认无疑会产生验证和测试的标准,而验证和测试通常又会帮助完成一些确认,特别是在系统测试阶段。
第八章 面向对象的软件测试
8.1.3 向对象软件测试的基本概念和传统测试模型类似,面向对象软件的测试遵循在软件开发各过程中不间断测试的思想,使开发阶段的测试与编码完成后的一系列测试融为一体。在开发的每一阶段进行不同级别、不同类型的测试,从而形成一条完整的测试链。根据面向对象的开发模型,结合传统的测试步骤的划分,形成了一种整个软件开发过程中不断进行测试的测试模型,
使开发阶段的测试与编码完成后的单元测试、集成测试、系统测试成为一个整体。面向对象的开发模型突破了传统的瀑布模型,将开发分为面向对象分析( OOA),面向对象设计( OOD),和面向对象编程
( OOP)三个阶段。分析阶段产生整个问题空间的抽象描述,在此基础上,进一步归纳出适用于面向对象编程语言的类和类结构,最后形成代码。由于面向对象的特点,采用这种开发模型能有效的将分析设计的文本或图表代码化,不断适应用户需求的变动。针对这种开发模型,结合传统的测试步骤的划分,本文建议一种整个软件开发过程中不断测试的测试模型,使开发阶段的测试与编码完成后的单元测试、
集成测试、系统测试成为一个整体。测试模型如下图所示:
第八章 面向对象的软件测试
8.1.3 向对象软件测试的基本概念图 8-1 面向对象测试结构图
0 面向对象编程
OOA Test,面向对象分析的测试 OOD Test,面向对象设计的测试
OOP Test,面向对象编程的测试 OO Unit Test,面向对象单元测试
OO Integrate Test,面向对象集成测试 OO System Test,面向对象系统测试第八章 面向对象的软件测试
8.1.3 向对象软件测试的基本概念在面向对象软件测试中,OOA(面向对象分析)全面地将问题空间中实现的功能进行现实抽象化,将问题空间中的实例抽象为对象,用对象的结构反映问题空间的复杂关系,用属性和服务表示实例的特殊性和行为。 OOA的结果是为后面阶段类的选定和实现、类层次结构的组织和实现提供平台。其测试重点在于完整性和冗余性,包括对认定对象的测试、对认定结构的测试、对认定主题的测试、对定义的属性和实例关联的测试,对定义的服务和消息关联的测试。 OOD(面向对象设计)建立类结构或进一步构造类库,实现分析结果对问题空间的抽象。 OOD确定类和类结构不仅能够满足当前需求分析的要求,更主要的是通过重新组合或加以适当的补充,方便实现功能的重用和扩增。
包括测试认定的类、测试类层次结构(类的泛化继承和关联)和测试类库。 OOP(面向对象实施)是软件的计算机实现,根据面向对象软件的特性,可以忽略类功能实现的细节,将测试集中在类功能的实现和相应的面向对象程序风格即数据成员的封装性测试和类的功能性测试上。如果程序是用 C++等面向对象语言实现,主要就是对类成员函数的测试。
第八章 面向对象的软件测试
8.1.3 向对象软件测试的基本概念面向对象单元测试是进行面向对象集成测试的基础。面向对象集成测试主要对系统内部的相互服务进行测试,如成员函数间的相互作用,类间的消息传递等。面向对象集成测试不但要基于面向对象单元测试,更要参见 OOD或 OOD Test结果。面向对象系统测试是基于面向对象集成测试的最后阶段的测试,主要以用户需求为测试标准,需要借鉴 OOA或 OOA Test结果。
第八章 面向对象的软件测试
8.2 面向对象测试的内容与范围面向对象软件测试各阶段的测试构成一个相互作用的整体,但其测试的主体、方向和方法各有不同,本文接下来将从面向对象分析的测试,面向对象设计的测试,面向对象编程的测试,面向对象单元测试,
面向对象集成测试,面向对象系统测试六个方面分别介绍对面向对象软件的测试。
第八章 面向对象的软件测试
8.2 面向对象测试的内容与范围
8.2.1 面向对象分析的测试 (OOA Test)
8.2.2 面向对象设计的测试 (OOD Test)
8.2.3 面向对象编程的测试 (OOP Test)
8.2.4 面向对象的单元测试 (OO Unit Test)
8.2.5 面向对象的集成测试 (OO Integrate Test)
8.2.6 面向对象的系统测试 (OO System Test)
8.2.7 面向对象的其他测试第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
传统的面向过程分析是一个功能分解的过程,是把一个系统看成可以分解的功能的集合。这种传统的功能分解分析法的着眼点在于一个系统需要什么样的信息处理方法和过程,以过程的抽象来对待系统的需要。而面向对象分析( OOA)是 "把 E-R图和语义网络模型,即信息造型中的概念,与面向对象程序设计语言中的重要概念结合在一起而形成的分析方法 ",最后通常是得到问题空间的图表的形式描述。
OOA直接映射问题空间,全面的将问题空间中实现功能的现实抽象化。
将问题空间中的实例抽象为对象(不同于 C++中的对象概念),用对象的结构反映问题空间的复杂实例和复杂关系,用属性和服务表示实例的特性和行为。对一个系统而言,与传统分析方法产生的结果相反,
行为是相对稳定的,结构是相对不稳定的,这更充分反映了现实的特性。 OOA的结果是为后面阶段类的选定和实现,类层次结构的组织和实现提供平台。因此,OOA对问题空间分析抽象的不完整,最终会影响软件的功能实现,导致软件开发后期大量可避免的修补工作;而一些冗余的对象或结构会影响类的选定、程序的整体结构或增加程序员不必要的工作量。因此,本文对 OOA的测试重点在其完整性和冗余性。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
尽管 OOA的测试是一个不可分割的系统过程,
为叙述的方便,对 OOA阶段的测试划分为以下五个方面:
对确定类和对象的范围的测试
对确定结构范围的测试
对确定主题范围的测试
对确定属性和实例关联的测试
对确定服务和消息关联的测试第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
1.对确定类和对象的范围的测试确定类与对象就是在实际问题的分析中高度地抽象和封装能反映问题域和系统任务的特征的类和对象。对它的测试可以从如下方面考虑:
⑴ 抽象的对象是否全面,是否是现实问题空间中所有涉及到的实例都反映在认定的抽象对象中。
⑵ 抽象出的对象是否具有多个属性。只有一个属性的对象通常应看成其他对象的属性,而不是抽象为独立的对象。
⑶ 对抽象为同一对象的实例是否有共同的,区别于其他实例的共同属性。
⑷ 对抽象为同一对象的实例是否提供或需要相同的服务,如果服务随着不同的实例而变化,认定的对象就需要分解或利用继承性来分类表示。
(5) 抽象的对象的名称应该尽量准确,适用。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
如何在众多调查资料中进行分析并确定类与对象呢?解决这一问题的方法一般包含如下几个方面:
(1)基础素材。系统调查的所有图表、文件、说明以及分析人员的经验、学识都是 OOA分析的基础素材。
(2)潜在的对象。在对基础素材的分析中,哪种内容是潜在的,并且有可能被抽象地封装成对象与类呢?一般说来下列因素都是潜在的对象:结构、业务、系统、实体、应记忆的事件等。
(3)确定对象。 初步分析选定对象以后,就通过一个对象和其它对象之间关系的角度来进行检验,并最后确定它。
(4)图形表示。用图形化方法表示确定的对象和类。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
2.对确定结构范围的测试结构表示问题空间的复杂程度。标识结构的目的是便于管理问题域模型。在 OOA中,结构是指泛化-特化结构和整体-部分结构两部分的总和。
( 1)确定泛化-特化结构(分类结构)
泛化-特化结构有助于刻画出问题空间的类成员层次。继承的概念是泛化-特化结构的一个重要组成部分。继承提供了一个用于标识和表示公共属性与服务的显式方法。在一个泛化-特化结构内,继承使共享属性或共享服务、增加属性或增加服务成为可能。
定义泛化-特化结构时,要分析在问题空间和系统责任的范围内,通用类是否表达了专用类的共性,专用类是否表示了个性。
图 8-2给出的是泛化-特化结构。其中,“发表的文章”和“接受的文章”是特殊化类,“文章”是一般化类。特殊化类是一般化类的派生类,一般化类是特殊化类的基类。分类结构具有继承性,一般化类和对象的属性和服务一旦被识别,即可在特殊化类和对象中使用。文章发表的文章接受的文章第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
文章发表的文章 接受的文章图 8-2 泛化-特化结构图第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
( 2)确定整体-部分结构(组装结构)
整体-部分结构表示一个对象怎样作为别的对象的一部分,和对象怎样组成更大的对象,与我们在系统工程中划分子系统结构的思路基本一致。
图 8-3说明报社是由采访组、编辑室和印刷厂等几个部门组成,同时也指出,一个报社只有一个编辑室,一个印刷厂,但可以有一至多个采访组。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
1
报社采访组 编辑室 印刷厂
1
11,m 1
图 8-3整体-部分结构
1
分类结构体现了问题空间中实例的一般与特殊的关系,组装结构体现了问题空间中实例整体与局部的关系。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
( 3)从如下方面对认定的分类结构的测试。
自上而下的派生关系,对于结构中的一种对象,尤其是处于高层的对象,是否能派生出下一层对象。
自底向上的抽象关系:对于结构中的一种对象,尤其是处于同一底层的对象,是否能抽象出在现实中有意义的更一般的上层对象。
( 4)从如下方面对认定的组装结构的测试。
整体(对象)和部件(对象)的组装关系是否符合现实的关系。
整体(对象)的部件(对象)是否在考虑的问题空间中有实际应用。
整体(对象)中是否遗漏了反映在问题空间中有用的部件(对象)。
部件(对象)是否能够在问题空间中组装新的有现实意义的整体(对象)。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
3.对确定主题范围的测试在 OOA中主题是一种指导研究和处理大型复杂模型的机制。它有助于分解系统,
区别结构,避免过多的信息量同时出现所带来的麻烦。主题的确定可以帮助人们从一个更高的层次上来观察和表达系统的总体模型。
主题如同文章对各部分内容的概要。对主题层的测试应该考虑以下方面:
( 1) 贯彻 George Miller 的 "7+2"原则。即如果主题个数超过 7个,就要求对有较密切属性和服务的主题进行归并。
( 2)主题所反映的一组对象和结构是否具有相同和相近的属性和服务。
( 3)认定的主题是否是对象和结构更高层的抽象,是否便于理解 OOA结果的概貌(尤其是对非技术人员的 OOA 结果读者)。
( 4)主题间的消息联系(抽象)是否代表了主题所反映的对象和结构之间的所有关联。
在测试中,首先应该考虑:为每一个结构相应地增设一个主题;为每一个对象相应地增设一个主题。如果主题的个数过多,则需进一步精炼主题。根据需要,可以把紧耦合的主题合在一起抽象一个更高层次的模型概念供读者理解。然后,列出主题及主题层上各主题之间的消息连接。最后,对主题进行编号,在层次图上列出主题以指导读者从一个主题到另一个主题。每一层都组织成按主题划分的图。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
4.对确定属性和实例关联的测试在 OOA中属性被用来定义反映问题域的特点的任务。定义属性是通过确认信息和关系来完成的,它们和每个实例有关。对属性和实例关联的测试从如下方面考虑:
( 1)定义的属性是否对相应的对象和分类结构的每个现实实例都适用。
( 2)定义的属性在现实世界是否与这种实例关系密切。
( 3)定义的属性在问题空间是否与这种实例关系密切。
( 4)定义的属性是否能够不依赖于其他属性被独立理解。
( 5)定义的属性在分类结构中的位臵是否恰当,低层对象的共有属性是否在上层对象属性体现。
( 6)在问题空间中每个对象的属性是否定义完整。
( 7)定义的实例关联是否符合现实。
( 8)在问题空间中实例关联是否定义完整,特别需要注意一对多和多对多的实例关联。
具体方法如下:
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
① 确定属性的范围首先要确定划分给每一个对象的属性,明确某个属性究竟描述哪个对象,要保证最大稳定性和模型的一致性,其次,确定属性的层次,通用属性应放在结构的高层,特殊属性放在低层。如果一个属性适用于大多数的特殊分类,
可将其放在通用的地方,然后在不需要的地方把它覆盖(即用,X” 等记号指出不需要继承该属性),如果发现某个属性的值有时有意义,有时却不适用,
则应考虑分类结构,根据发现的属性,还可以进一步修订对象。
②实例连接实例连接是一个问题域的映射模型,该模型反映了某个对象对其它对象的需求。通过实例连接可以加强属性对类与状态的描述能力。
实例连接有一对一( 1,1)、一对多 (1,M)和多对多 (M,M)三种,分别表示一个实例可对应一个或多个实例,这种性质叫多重性。例如,一个车主拥有一辆汽车,则车主到汽车的实例连接是 1,1的;一个车主拥有多辆汽车,则是 1,M的。
实例连接的表示方法非常简单,只需在原类和对象的基础上用直线相连接,
并在直线的两端用数字标志出它们之间的上下限关系即可。例如在车辆和执照事故管理系统中,可以将车辆拥有者和法律事件两个类 &对象实例连接如图
8-4形式。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
1,m
m,1
owner person
telephone
legal event
registration date
图 8-4 车辆拥有者和法律事件的实例连接
③ 详细说明属性和实例连接的约束用名字和描述说明属性,属性可分成四类;描述性的、定义性的、
永远可导出的和偶而可导出的。实例连接的约束是指多重性与参与性。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
5.对确定服务和消息关联的测试对象收到消息后所能执行的操作称为它可提供的服务。它描述了系统需要执行的处理和功能。定义服务的目的在于定义对象的行为和对象之间的通信(消息连接)。事实上,两个对象之间可能存在着由于通信需要而形成的关系,即为消息连接。消息连接表示从一个对象发送消息到另一个对象,由那个对象完成某些处理。
确定服务的具体解决方法主要包括四个基本步骤:在分析中识别对象状态;识别所要求的服务;识别消息连接和指定服务。
( 1)识别对象状态在系统运行过程中,对象从被创建到释放要经历多种不同的状态。对象的状态是由属性的值来决定和表示的。一个对象状态是属性值的标识符,它反映了对象行为的改变。
识别对象状态的方法一般通过检查每一个属性的所有可能取值,确定系统的职责是否针对这些可能的值会有不同的行为;检查在相同或类似的问题论域中以前的分析结果,看是否有可直接复用的对象状态;
利用状态迁移图描述状态及其变化。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
( 2)识别所要求的服务必要的服务可分为两大类:简单的服务和复杂的服务。
简单的服务是每一个类或对象都应具备这样的服务,在分析模型中,
这些服务不必画出,如建立和初始化一个新对象,释放或删除一个对象等。
复杂的服务分为两种:计算服务和监控服务,必须在分析模型中显式地给出,计算服务是利用对象的属性值计算,以实现某种功能;监控服务主要处理对外部系统的输入 /输出,外部设备的控制和数据的存取。
为了标识必要的服务,需要注意检查每一个对象的所有状态,确定此对象在不同的状态值下要负责执行哪些计算、要做哪些监控,以便能够弄清外部系统或设备的状态将如何改变,对这些改变应当做什么响应;检查在相同或类似的问题论域中以前的分析结果,看是否有可直接复用的服务。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
( 3)识别消息连接消息连接是指从一个对象向另一个对象发送消息,并且使得某一处理功能,所需的处理是在发送对象的方法中指定的,并且在接收对象的方法中详细定义了的。
识别消息连接的方法及策略是检查在相同或类似的问题论域中以前分析的结果,看是否有可复用的消息连接。对于每一个对象,查询该对象需要哪些对象的服务,从该对象画一箭头到那个对象;查询哪个对象需要该对象的服务,从那个对象画一箭头到该对象;循消息连接找到下一个对象,重复以上步骤直至检查完全部对象。当一个对象将一个消息传送给另一个对象时,另一个对象又可传送一个消息给另一个对象,如此下去就可得到一条执行线索。检查所有的执行线索,确定哪些是关键执行线索,以检查模型的完备性。
( 4)定义服务在确定了对象的状态、所要执行的内容和消息后,具体如何执行操作呢? OOA提供了模板式的方法描述方式。这是一种类似程序框图的工具。它主要用定义方法和定义例示来实现。如图 8-5所示。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
Specification
attribute 条件
… (if,precondition,trigger,terminate)
external input
external output 正文块
additional constraints (context)
notes
method(name & method chart) 循环
… (while,do,repeat,trrgger/terminate)
traceability codes
applicable store codes 连接
time requirements (connection)
图 8-5 定义方法和定义例示图 8-5 定义方法和定义例示
(b)(a)
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
对定义的服务和消息关联的测试从如下方面进行:
对象和结构在问题空间的不同状态是否定义了相应的服务。
对象或结构所需要的服务是否都定义了相应的消息关联。
定义的消息关联所指引的服务提供是否正确。
沿着消息关联执行的线程是否合理,是否符合现实过程。
定义的服务是否重复,是否定义了能够得到的服务。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
面向对象设计( OOD)是以 OOA为基础归纳出的类为基础,建立类结构甚至进一步构造成类库,实现了分析结果对问题空间的抽象。 OOD 归纳的类,可以是对象简单的延续,也可以是不同对象的相同或相似的服务。 OOD确定类和类结构不仅是满足当前需求分析的要求,更重要的是通过重新组合或加以适当的补充或删减,能方便实现功能的重用和扩增,以不断适应用户的要求。 OOD的基本目标是改进设计、增进软件生产效率、提高软件质量以及加强可维护性。如果模型的质量很高对项目来说就很有价值,但是如果模型有错误,那么它对项目的危害就无可估量。
以下面向对象设计模型是由 Coad和 Yourdon提出的。该模型由四个部分和五个层次组成。如下图 8-6所示。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
数据管理部件主题层结构层操作层服务层人机交互部件数据管理部件任务管理部件 类与对象层图 8-6 OOD系统模型其四个组成部分是问题空间部件 (Problem Domain Component,
简称 PDC)、人机交互部件 (Human Interaction Component,简称
HIC)、任务管理部件 (Task Management Component,简称 TMC)和数据管理部件 (Data Management Component,简称 DMC)。五个层次是主题层、类与对象层、结构层、属性层和服务层,这五个层次分别对应 Coad的面向对象分析方法中的确定对象、确定结构、定义主题、定义属性、确定服务等行动。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
所以,对 OOD的测试,建议从如下方面考虑:
确定测试的问题域。
人机交互部分设计的测试
对认定的类的测试。
对构造的类层次结构的测试。
对类库的支持的测试。
对测试结果以及对模型的测试覆盖率(基于某中标准)进行评估。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
1,确定测试的问题域在面向对象设计中,面向对象分析( OOA)的结果恰好符合面向对象设计( OOD)的问题空间部分,因此,OOA的结果就是 OOD部分模型中的一个完整部分。但是,为了解决一些特定设计所需要考虑的实际变化,可能要对 OOA结果进行一些改进和增补。主要是根据需求的变化,
对 OOA产生模型中的某些类与对象、结构、属性、操作进行组合与分解。要考虑对时间与空间的折衷、内存管理、开发人员的变更、以及类的调整等。另外,根据 OOD的附加原则,增加必要的类、属性和关系。
( 1)复用设计根据问题解决的需要,把从类库或其他来源得到的既存类增加到问题解决方案中去。既存类可以是用面向对象程序语言编写出来的,也可以是用其他语言编写出来的可用程序。要求标明既存类中不需要的属性和操作,把无用的部分维持到最小限度。并且增加从既存类到应用类之间的泛化-特化的关系。进一步地,把应用中因继承既存类而成为多余的属性和操作标出。还要修改应用类的结构和连接,必要时把它们变成可复用的既存类。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
( 2)把问题论域相关的类关联起来在设计时,从类库中引进一个根类,做为包容类,把所有与问题论域有关的类关联到一起,建立类的层次。把同一问题论域的一些类集合起来,存于类库中。
( 3)加入一般化类以建立类间协议有时,某些特殊类要求一组类似的服务。在这种情况下,应加入一个一般化的类,定义为所有这些特殊类共用的一组服务名,这些服务都是虚函数。在特殊类中定义其实现。
( 4)调整继承支持级别在 OOA阶段建立的对象模型中可能包括有多继承关系,但实现时使用的程序设计语言可能只有单继承,甚至没有继承机制,这样就需对分析的结果进行修改。可通过对把特殊类的对象看做是一个一般类对象所扮演的角色,通过实例连接把多继承的层次结构转换为单继承的层次结构;把多继承的层次结构平铺,成为单继承的层次结构等方法。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
( 5)改进性能提高执行效率和速度是系统设计的主要指标之一。有时,必须改变问题论域的结构以提高效率。如果类之间经常需要传送大量消息,可合并相关的类以减少消息传递引起的速度损失。增加某些属性到原来的类中,或增加低层的类,以保存暂时结果,避免每次都要重复计算造成速度损失。
( 6)加入较低层的构件在做面向对象分析时,分析员往往专注于较高层的类和对象,避免考虑太多低层的实现细节。但在做面向对象设计时,设计师在找出高层的类和对象时,
必须考虑到底需要用到哪些较低层的类和对象。
针对上述问题域的定义,制定如下测试策略:
首先制订检查的范围和深度。范围将通过描述材料的实体或一系列详细的用例来定义。对小的项目来说,范围可以是整个模型。深度将通过指定需要测试的模型( MUT)的某种 UML(统一建模语言)图的集合层次中的级别来定义。
然后为每一个评价标准开发测试用例,标准在应用时使用基本模型的内容作为输入。这种从用户用例模型出发的方式对许多模型的测试用例来说是一个很好的出发点。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
2.人机交互部分的设计( HIC)的测试通常在 OOA阶段给出了所需的属性和操作,在设计阶段必须根据需求把交互的细节加入到用户界面的设计中,包括有效的人机交互所必需的实际显式和输入。人机交互部分的设计决策影响到人的感情和精神感受,测试 HIC的策略由以下几方面构成:用户分类;描述人及其任务的脚本;设计命令层;设计详细的交互;继续做原型;设计 HIC类;
根据图形用户界面( GUI)进行设计。
( 1)用户分类进行用户分类的目的是明确使用对象,针对不同的使用对象设计不同的用户界面,以适合不同用户的需要。分类的原则有:
按技能层次分类:外行 /初学者 /熟练者 /专家;
按组织层次分类:行政人员 /管理人员 /专业技术人员 /其他办事员;
按职能分类:顾客 /职员。
( 2)描述人及其任务脚本对以上定义的每一类人,描述其身份、目的、特征、关键的成功因素、熟练程度及任务剧本。 第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
例 8-1 描述分析员:
什么人:分析员目的:要求一个工具来辅助分析工作(摆脱繁重的画图和检查图的工作)。
特点:年龄= 42岁;教育水平=大学;限制=不要微型打印。
成功的关键因素:工具应当使分析工作顺利进行;工具不应与分析工作冲突;
工具应能捕获假设和思想,能适时做出折衷;应能及时给出模型各个部分的文档,这与给出需求同等重要。
熟练程度:专家。
任务脚本:主脚本-识别“核心的”类和对象;识别“核心”结构;在发现了新的属性或操作时随时都可以加进模型中去。检验模型-打印模型及其全部文档。
( 3)设计命令层研究现行的人机交互活动的内容和准则,建立一个初始的命令层,再细化命令层:这时,要考虑:排列命令层次,把使用最频繁的操作放在前面,按照用户工作步骤排列;通过逐步分解,找到整体-部分模式,帮助在命令层中对操作进行分块;根据人们短期记忆的“”或“每次记忆 3块 /每块 3项”的特点,组织命令层中的服务,宽度与深度不宜太大,减少操作步骤。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
( 4)设计详细的交互用户界面设计有若干原则,一般有:一致性,操作步骤少,不要“哑播放”:即每当用户等待系统完成一个活动时,要给出一些反馈信息,
说明工作正在进展,以及进展的程度。:在操作出现错误时,要恢复或部分恢复原来的状态。提供联机的帮助信息。并具有趣味性,在外观和感受上,尽量采用图形界面,符合人类习惯,有一定吸引力。
( 5)继续做原型做人机交互原型是 HIC设计的基本工作,界面应使人花最少的时间去掌握其使用技法,做几个可候选的原型,让人们一个一个地试用,要达到“臻于完善”,由衷地满意。
( 6)设计 HIC类设计 HIC类,从组织窗口和部件地人机交互设计开始,窗口作基本类、
部件作属性或部分类。特殊窗口作特殊类。每个类包括窗口的菜单条、
下拉菜单、弹出菜单的定义,每个类还定义了用来创造菜单、加亮选择等所需的服务。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
( 7)根据 GUI(图形用户界面)进行设计图形用户界面区分为字型、坐标系统和事件。图形用户界面的字型是字体、字号、样式和颜色的组合。坐标系统主要因素有原点(基准点)、显式分辨率、显示维数等。事件则是图形用户界面程序的核心,
操作将对事件做出响应,这些事件可能是来自人的,也可能是来自其他操作的。事件的工作方式有两种:直接方式和排队方式。所谓直接方式,是指每个窗口中的项目有它自己的事件处理程序,一旦事件发生,则系统自动执行相应的事件处理程序。所谓排队方式,是指当事件发生时系统把它排到队列中,每个事件可用一些子程序信息来激发。
应用可利用,next event” 来得到一个事件并执行它所需要的一切活动。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
3.对任务管理部分设计( TMC)的测试在 OOD中,任务是指系统为了达到某一设定目标而进行的一连串的数据操作(或服务),若干任务的并发执行叫做多任务。任务能简化并发行为的设计和编码,TMC的设计就是针对任务项,对一连串的数据操作进行定义和封装,
对于多任务要确定任务协调部分,以达到系统在运行中对各项任务进行合理组织与管理。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
( 1) TMC设计策略
①识别事件驱动任务。事件驱动任务是指睡眠任务(不占用 CPU),当某个事件发生时,任务被此事件触发,任务醒来做相应处理,然后又回到睡眠状态。
②识别时钟驱动任务。按特定的时间间隔去触发任务进行处理,如某些设备需要周期性的数据采集和控制。
③识别优先任务和关键任务。把它们分离开来进行细致的设计和编码,
保证时间约束或安全性。
④识别协调者。增加一个任务来协调诸任务,这个任务可以封装任务之间的协作。
⑤审查每个任务,使任务数尽可能少。
⑥定义每个任务:包括任务名、驱动方式、触发该任务的事件、时间间隔、如何通信等。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
( 2)设计步骤
①对类和对象进行细化,建立系统的 OOA/OOD工作表格。 OOA/OOD工作表格包括:某系统可选定的对象的条目,对该对象在 OOD部件中位臵的说明和注释等。
②审查 OOA/OOD工作表格,寻找可能被封装在 TMC中那些与特定平台有关的部分以及任务协调部分、通信的从属关系、消息、线程序列等。
③构建新的类。 TM部件设计的首要任务就是构建一些新的类,这些类建立的主要目的是处理并发执行、中断、调度以及特定平台有关的一些问题。
任务管理部件一般在信息系统中使用较少,在控制系统中应用较多。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
4.对数据管理部分设计( DMC)的测试数据管理部分提供了在数据管理系统中存储和检索对象的基本结构,包括对永久性数据的访问和管理。它分离了数据管理机构所关心的事项,包括文件、关系型 DBMS或面向对象 DBMS等。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
( 1)数据管理方法数据管理方法主要有 3种:文件管理、关系数据库管理和面向对象库数据管理。
① 文件管理:提供基本的文件处理能力。
② 关系数据库管理系统( RDBMS):关系数据库管理系统建立在关系理论的基础上,它使用若干表格来管理数据,使用特定操作,如 select(提取某些行),project(提取某些栏),join(联结不同表格中的行,再提取某些行)
等,可对表格进行剪切和粘贴。通常根据规范化的要求,可对表格和它们的各栏重新组织,以减少数据冗余,保证修改一致性数据不致出错。
③ 面向对象数据库管理系统( OODBMS):通常,面向对象的数据库管理系统以两种方法实现:一是扩充的 RDBMS,二是扩充的面向对象程序设计语言
( OOPL)。
扩充的 RDBMS主要对 RDBMS扩充了抽象数据类型和继承性,再加上一些一般用途的操作来创建和操纵类与对象。扩充的 OOPL对面向对象程序设计语言嵌入了在数据库中长期管理存储对象的语法和功能。这样,可以统一管理程序中的数据结构和存储的数据结构,为用户提供了一个统一视图,无需在它们之间做数据转换。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
( 2)数据管理部分的设计数据存储管理部分的设计包括数据存放方法的设计和相应操作的设计。
①数据存放设计数据存放有三种形式:文件存放方式、关系数据库存放方式和面向对象数据库存放方式,根据具体情况选用。
② 设计相应的操作为每个需要存储的对象及其类增加用于存储管理的属性和操作,在类及对象的定义中加以描述。通过定义,每个需要存储的对象将知道如何“存储我自己”。
为能充分发挥面向对象的继承共享特性,OOD的类层次结构,通常基于 OOA中产生的分类结构的原则来组织,着重体现父类和子类间一般性和特殊性。两者概念上的差异。在当前的问题空间,对类层次结构的主要要求是能在解空间构造实现全部功能的结构框架。为此,测试如下方面:
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
类层次结构是否含盖了所有定义的类;
是否能体现 OOA中所定义的实例关联;
是否能实现 OOA中所定义的消息关联;
子类是否具有父类没有的新特性;
子类间的共同特性是否完全在父类中得以体现。
第八章 面向对象的软件测试
8.2.3 面向对象编程的测试 (OOP Test)
典型的面向对象程序具有继承、封装和多态的新特性,这使得传统的测试策略必须有所改变。封装是对数据的隐藏,外界只能通过被提供的操作来访问或修改数据,这样降低了数据被任意修改和读写的可能性,降低了传统程序中对数据非法操作的测试。继承是面向对象程序的重要特点,继承使得代码的重用率提高,同时也使错误传播的概率提高。继承使得传统测试遇见了这样一个难题:对继承的代码究竟应该怎样测试?(参见面向对象单元测试)。多态使得面向对象程序对外呈现出强大的处理能力,但同时却使得程序内“同一”函数的行为复杂化,测试时不得不考虑不同类型具体执行的代码和产生的行为。
面向对象程序是把功能的实现分布在类中。能正确实现功能的类,通过消息传递来协同实现设计要求的功能。正是这种面向对象程序风格,
将出现的错误能精确的确定在某一具体的类。因此,在面向对象编程
( OOP)的测试中,忽略类功能实现的细则,将测试的目光集中在类功能的实现和相应的面向对象程序风格,主要体现为以下两个方面
(假设编程使用 C++语言)。
第八章 面向对象的软件测试
8.2.3 面向对象编程的测试 (OOP Test)
数据成员是否满足数据封装的要求类是否实现了要求的功能
1.数据成员是否满足数据封装的要求数据封装是数据和数据有关的操作的集合。检查数据成员是否满足数据封装的要求,基本原则是数据成员是否被外界(数据成员所属的类或子类以外的调用)直接调用。更直观的说,当改变数据成员的结构时,是否影响了类的对外接口,是否会导致相应外界必须改动。值得注意的是有时强制的类型转换会破坏数据的封装特性。
第八章 面向对象的软件测试
8.2.3 面向对象编程的测试 (OOP Test)
例 8-2:
class Hiden
{
private,
int a=1;
char *p= "hiden";
}
class Visible
{
public,
int b=2;
char *s= "visible";
}
.,
Hiden pp;
Visible *qq=(Visible *)&pp;
在上面的程序段中,pp的数据成员可以通过 qq被随意访问,这就破坏了数据的封装性。
第八章 面向对象的软件测试
8.2.3 面向对象编程的测试 (OOP Test)
2.类是否实现了要求的功能类所实现的功能,都是通过类的成员函数执行。在测试类的功能实现时,应该首先保证类成员函数的正确性。单独的看待类的成员函数,
与面向过程程序中的函数或过程没有本质的区别,几乎所有传统的单元测试中所使用的方法,都可在面向对象的单元测试中使用。具体的测试方法在面向对象的单元测试中介绍。类函数成员的正确行为只是类能够实现要求的功能的基础,类成员函数间的作用和类之间的服务调用是单元测试无法确定的。因此,需要进行面向对象的集成测试。
具体的测试方法在面向对象的集成测试中介绍。需要注意的是,测试类的功能,不能仅满足于代码能无错运行或被测试类能提供的功能无错,应该以所做的 OOD结果为依据,检测类提供的功能是否满足设计的要求,是否有缺陷。必要时(如通过 OOD结仍不清楚明确的地方)
还应该参照 OOA的结果,以之为最终标准。
第八章 面向对象的软件测试
8.2.4 面向对象的单元测试 (OO Unit Test)
传统的单元测试是针对程序的函数、过程或完成某一定功能的程序块。面向对象的单元测试对象是软件设计的最小单位 —— 类。单元测试的依据是详细设计,单元测试应对类中所有重要的属性和方法设计测试用例,以便发现类内部的错误。单元测试多采用白盒测试技术,系统内多个类块可以并行地进行测试。沿用单元测试的概念,实际测试类成员函数。一些传统的测试方法在面向对象的单元测试中都可以使用。如等价类划分法,因果图法,边值分析法,
逻辑覆盖法,路径分析法等等。
第八章 面向对象的软件测试
8.2.4 面向对象的单元测试 (OO Unit Test)
1.单元测试的内容面向对象的单元就是类,单元测试实际就是对类的测试。类测试的目的主要是确保一个类的代码能够完全满足类的说明所描述的要求。对一个类进行测试以确保它只做规定的事情,对此给与关注的多少,取决于提供额外的行为的类相关联的风险。每个类都封装了属性(数据)
和管理这些数据的操作(也被称做方法或服务)。一个类可以包含许多不同的操作,一个特殊的操作可以出现在许多不同的类中,而不是个体的模块。传统的单元测试只能测试一个操作(功能),而在面向对象单元测试中,一个操作功能只能作为一个类的一部分,类中有多个操作(功能),就要进行多个操作的测试。另外,父类中定义的某个操作被多个子类继承,不同子类中某个操作在使用时又有细微的不同,所以还必须对每个子类中某个操作进行测试。对类的测试强调对语句应该有 100%的执行代码覆盖率。在运行了各种类的测试用例后,
如果代码的覆盖率不完整,这可能意味着该类包含了额外的文档支持的行为,需要增加更多的测试用例来进行测试。
第八章 面向对象的软件测试
8.2.4 面向对象的单元测试 (OO Unit Test)
2.方法的测试在测试类的功能实现时,应该首先保证类成员函数的正确性。类函数成员的正确行为只是类能够实现要求的功能的基础,类成员函数间的作用和类之间的服务调用是单元测试无法确定的。因此,需要进行面向对象的集成测试。测试时主要考虑封装在类中的一个方法对数据进行的操作,可以采用传统的模块测试方法,但方法是封装在类中,并通过向所在对象发消息来执行,它的执行与状态有关,特别是在操作的多态性时,设计测试用例时要考虑设臵对象的初态,并且要设计一些函数来观察隐蔽的状态值。
类的行为是通过其内部方法来表现的,方法可以看作传统测试中的模块。因此传统针对模块的设计测试案例的技术,例如逻辑覆盖、等价划分、边界值分析和错误推测等方法,仍然可以作为测试类中每个方法的主要技术。面向对象中为了提高方法的重用性,每个方法所实现的功能应尽量小,每个方法常常只由几行代码组成,控制比较简单,因此测试用例的设计相对比较容易。
在传统的结构化系统中需要设计一个能调用被测模块的主程序来实现对模块的测试,而在面向对象系统中方法的执行是通过消息来驱动执行的,要测试类中的方法,必须用一个驱动程序对被测方法发一条消息以驱动其执行,如果被测模块或方法中有调用其它的模块或方法,则都需要设计一个模拟被调子程序功能的存根程序。驱动程序、存根程序及被测模块或方法组成一个独立的可执行的单元。
第八章 面向对象的软件测试
8.2.4 面向对象的单元测试 (OO Unit Test)
方法测试中有两个方面要加以注意。首先,方法执行的结果并不一定返回调用者,有的可能是改变被测对象的状态 (类中所有属性值 ) 。
状态是外界不可见的,为了测试对象状态的变化是否已经被执行,在驱动程序中还必须给对象发送一些额外的信息。其次,除了类中自己定义的方法,还可能存在从基类继承来的方法,这些方法虽然在基类中已经测试过,但派生类往往需要再次测试。
在面向对象软件中,在保证单个方法功能正确的基础上,还应该测试方法之间的协作关系。操作被封装在类中,对象彼此间通过发送消息启动相应的操作。但是,对象并没有明显地规定用什么次序启动它的操作才是合法的。这时,对象就像一个有多个入口的模块,因此,必须测试方法依不同次序组合的情况。但是为了提高方法的重用性,设计方法的一个准则是提高方法的内聚,即一个方法应该只完成单个功能,因此一个类中方法数一般较多。当类中方法数为 n时,全部的次序组合数为 2n。因此,测试完全的次序组合通常是不可能的,在设计测试用例时,同样可以利用等价划分、边界值、错误推测等技术从各种可能启动操作的次序组合中,选出最可能发现属性和操作错误的若干种情况,着重进行测试。测试步骤与单个方法测试步骤类似。
第八章 面向对象的软件测试
8.2.4 面向对象的单元测试 (OO Unit Test)
同样,对于继承来的方法与新方法的协作,也要加以测试。
因为随着新方法的加入,增加了启动操作次序的组合情况,
某些启动序列可能破坏对象的合法状态。所以,对于继承来的方法也需要仔细测试它们是否能够完成所要完成的功能。
由上述可见,如果以方法为单元进行测试,那么面向对象的单元测试就相当于归结为了传统的过程的单元测试了。
以前的方法都可以使用。
需要考虑的是,运行测试用例时候,必须提供能够实例化的桩类,以及起驱动器作用的“主程序”类,来提供和分析测试用例。
第八章 面向对象的软件测试
8.2.5 面向对象的集成测试 (OO Integrate Test)
传统的集成测试,是通过各种集成策略集成各功能模块进行测试,一般可以在部分程序编译完成的情况下进行。而对于面向对象程序,相互调用的功能是散布在程序的不同类中,类通过消息相互作用申请和提供服务。类的行为与它的状态密切相关,状态不仅仅是体现在类数据成员的值,也许还包括其他类中的状态信息。由此可见,类相互依赖极其紧密,根本无法在编译不完全的程序上对类进行测试。所以,
面向对象的集成测试通常需要在整个程序编译完成后进行。此外,面向对象程序具有动态特性,程序的控制流往往无法确定,因此也只能对整个编译后的程序做基于黑盒子的集成测试。
把一组相互有影响的类看作一个整体称为类簇。类簇测试主要根据系统中相关类的层次关系,检查类之间的相互作用的正确性,即检查各相关类之间消息连接的合法性、子类的继承性与父类的一致性、动态绑定执行的正确性、类簇协同完成系统功能的正确性等等。其测试有两种不同策略。
第八章 面向对象的软件测试
8.2.5 面向对象的集成测试 (OO Integrate Test)
1.基于类间协作关系的横向测试。
由系统的一个输入事件作为激励,对其触发的一组类进行测试,执行相应的操作 /消息处理路径,
最后终止于某一输出事件。应用回归测试对已测试过的类集再重新执行一次,以保证加入新类时不会产生意外的结果。
2.基于类间继承关系的纵向测试。
首先通过测试独立类 (是系统中已经测试正确的某类 )来开始构造系统,在独立类测试完成后,下一层继承独立类的类 (称为依赖类 ) 被测试,这个依赖类层次的测试序列一直循环执行到构造完整个系统。
第八章 面向对象的软件测试
8.2.5 面向对象的集成测试 (OO Integrate Test)
集成测试在面向对象系统中属于应用生命周期的一个阶段,可在两个层次上进行。第一层对一个新类进行测试,以及测试在定义中所涉及的那些类的集成。设计者通常用关系 is a,is part 和 refers to 来描述类与类之间的依赖,并隐含了类测试的顺序。首先测试基础类,
然后使用这些类的类接着测试,再按层次继续测试,每一层次都使用了以前已定义和测试过的类作为部件块。对于面向对象领域中集成测试的特别要求是:应当不需要特别地编写代码就可把在当前的软件开发中使用的元素集合起来。因此,其测试重点是各模块之间的协调性,
尤其是那些从没有在一起的类之间的协调性。
集成测试的第二层是将各部分集合在一起组成整个系统进行测试。以
C ++ 语言编写的应用系统为例,通常在其主程序中创建一些高层类和全局类的实例,通过这些实例的相互通讯从而实现系统的功能。对于这种测试所选择的测试用例应当瞄准待开发软件的目标而设计,并且应当给出预期的结果,以确定软件的开发是否与目标相吻合。
第八章 面向对象的软件测试
8.2.5 面向对象的集成测试 (OO Integrate Test)
面向对象的集成测试能够检测出相对独立的单元测试无法检测出的那些类相互作用时才会产生的错误。基于单元测试对成员函数行为正确性的保证,集成测试只关注于系统的结构和内部的相互作用。面向对象的集成测试可以分成两步进行:先进行静态测试,再进行动态测试。
静态测试主要针对程序的结构进行,检测程序结构是否符合设计要求。现在流行的一些测试软件都能提供一种称为 "可逆性工程 "的功能,即通过原程序得到类关系图和函数功能调用关系图,例如 International Software
Automation 公司的 Panorama-2 forWindows95,Rational公司的 Rose C++
Analyzer等,将 "可逆性工程 "得到的结果与 OOD的结果相比较,检测程序结构和实现上是否有缺陷。换句话说,通过这种方法检测 OOP是否达到了设计要求。
动态测试设计测试用例时,通常需要上述的功能调用结构图、类关系图或者实体关系图为参考,确定不需要被重复测试的部分,从而优化测试用例,减少测试工作量,使得进行的测试能够达到一定覆盖标准。测试所要达到的覆盖标准可以是:达到类所有的服务要求或服务提供的一定覆盖率;依据类间传递的消息,达到对所有执行线程的一定覆盖率;达到类的所有状态的一定覆盖率等。同时也可以考虑使用现有的一些测试工具来得到程序代码执行的覆盖率。
第八章 面向对象的软件测试
8.2.5 面向对象的集成测试 (OO Integrate Test)
具体设计测试用例,可参考下列步骤:
( 1) 先选定检测的类,参考 OOD分析结果,仔细出类的状态和相应的行为,类或成员函数间传递的消息,输入或输出的界定等。
( 2)确定覆盖标准。
( 3)利用结构关系图确定待测类的所有关联。
( 4)根据程序中类的对象构造测试用例,确认使用什么输入激发类的状态、使用类的服务和期望产生什么行为等。
值得注意,设计测试用例时,不但要设计确认类功能满足的输入,还应该有意识的设计一些被禁止的例子,确认类是否有不合法的行为产生,如发送与类状态不相适应的消息,要求不相适应的服务等。根据具体情况,动态的集成测试,有时也可以通过系统测试完成。
第八章 面向对象的软件测试
8.2.6 面向对象的系统测试 (OO System Test)
系统测试应该尽量搭建与用户实际使用环境相同的测试平台,应该保证被测系统的完整性,对临时没有的系统设备部件,也应有相应的模拟手段。系统测试时,应该参考
OOA分析的结果,对应描述的对象、属性和各种服务,检测软件是否能够完全 "再现 "问题空间。系统测试不仅是检测软件的整体行为表现,从另一个侧面看,也是对软件开发设计的再确认。
这里说的系统测试是对测试步骤的抽象描述。它体现的具体测试内容包括:
第八章 面向对象的软件测试
8.2.6 面向对象的系统测试 (OO System Test)
1.功能测试测试是否满足开发要求,是否能够提供设计所描述的功能,是否用户的需求都得到满足。功能测试是系统测试最常用和必须的测试,通常还会以正式的软件说明书为测试标准。
2.强度测试测试系统的能力最高实际限度,即软件在一些超负荷的情况,功能实现情况。如要求软件某一行为的大量重复、输入大量的数据或大数值数据、对数据库大量复杂的查询等。
3.性能测试测试软件的运行性能。这种测试常常与强度测试结合进行,需要事先对被测软件提出性能指标,如传输连接的最长时限、传输的错误率、
计算的精度、记录的精度、响应的时限和恢复时限等。
4.安全测试验证安装在系统内的保护机构确实能够对系统进行保护,使之不受各种非常的干扰。安全测试时需要设计一些测试用例试图突破系统的安全保密措施,检验系统是否有安全保密的漏洞。
第八章 面向对象的软件测试
8.2.6 面向对象的系统测试 (OO System Test)
5.恢复测试采用人工的干扰使软件出错,中断使用,检测系统的恢复能力,特别是通讯系统。恢复测试时,应该参考性能测试的相关测试指标。
可用性测试:测试用户是否能够满意使用。具体体现为操作是否方便,用户界面是否友好等。
6.安装 /卸载测试测试用户能否方便地安装 /卸载软件。
系统测试需要对被测的软件结合需求分析做仔细的测试分析,建立测试用例。
7.可用性测试:测试用户是否能够满意使用。具体体现为操作是否方便,用户界面是否友好等。
8.基于 UML的系统测试第八章 面向对象的软件测试
8.2.6 面向对象的系统测试 (OO System Test)
考查系统的规格说明,用例图,GUI状态图。分成下面四个层次:
( 1)构建用例与系统功能的关联矩阵,建立测试覆盖的初步标准,从对应于扩展基本用例的真实用例中导出测试用例。
( 2)通过所有真实用例开发测试用例。
( 3)用过有限状态机导出测试用例,有限状态机有 GUI外观有限状态机描述导出。
( 4)通过基于状态的事件表导出测试用例,这种工作必须对每个状态重复进行。
第八章 面向对象的软件测试
8.2.6 面向对象的系统测试 (OO System Test)
9.基于状态图的系统测试状态图是系统测试的很好的基础。问题是,UML将状态图规定为类级的。合成多个类的状态图得到一个系统级的状态图是很难的。一种可行的方法是,将每个类级的状态图转换成一组 EDPN,然后合成 EDPN。
第八章 面向对象的软件测试
8.2.7 面向对象的其他测试在面向对象测试中,除需要进行上面介绍的测试外,还应该进行如下测试。
1.基于故障的测试
2.基于脚本的测试
3.面向对象类的随机测试
4.类层次的分割测试第八章 面向对象的软件测试
8.3 面向对象软件测试技术与方法面向对象方法的使用日益普及,随之而来的面向对象软件的质量问题也越来越受到人们的重视。软件测试是提高软件质量的重要途径。但与面向对象软件的开发技术相比,面向对象软件的测试技术却仍处于初级阶段。
第八章 面向对象的软件测试
8.3 面向对象软件测试技术与方法
8.3.1分析和设计模型测试技术
8.3.2 类测试技术
8.3.3 类层次结构测试技术
8.3.4 对象交互测试技术第八章 面向对象的软件测试
8.3.1分析和设计模型测试技术面向对象软件开发的起始步骤是开发分析和设计模型。
UML(统一建模语言)能在面向对象技术开发中广泛应用,
也是因为构建模型能帮助开发者理解正在解决的问题;构建模型能帮助管理正在开发的系统的复杂性;分析和设计阶段建构的模型最后将对具体地实现起指导作用。如果模型的质量很高对项目来说就很有价值;但是如果模型有错误,那么它对项目的危害就无可估量。
分析与设计模型的测试主要是对分析与设计模型进行测试,
找出模型中的错误,其采用的方法是指导性审查 (guided
inspection)。指导性审查技术通过使用明确的测试用例为查找工作成果中的缺陷提供了客观的、系统的方法。是一种增强了的专为检验模型的检测技巧,也可用来验证模型是否能符合项目的需求。其基本步骤如下:
第八章 面向对象的软件测试
8.3.1分析和设计模型测试技术
定义测试位臵。
使用特定的策略从测试位臵选择测试值。
将测试值应用到被测试的产品中。
对测试结果以及对模型的测试覆盖率(基于某中标准)进行评估。
第八章 面向对象的软件测试
8.3.1分析和设计模型测试技术这些步骤经过具体化后形成下列详细步骤:
1.制订检查的范围和深度:范围将通过描述材料的实体或一系列详细的用例来定义。对小的项目来说,范围可以是整个模型。深度将通过指定须要测试的模型( MUT)的某种 UML图的集合层次中的级别来定义。
2.确定 MUT产生的基础:除原始模型之外,所有的 UMT的基础是前一开发阶段创建的一系列模型:比如,应用分析模型就是以域分析模型和用例模型为基础。起初模型则是基于所选择的一组人头脑里的知识。
3.为每一个评价标准开发测试用例,标准在应用时使用基本模型的内容作为输入。这种从用户用例模型出发的方式对许多模型的测试用例来说是一个很好的出发点。
4.为测量测试的覆盖率建立标准。比如对一个类图来说,如果图中每一个类都被测试到了,那么覆盖率就算不错了。
5.使用合适的检查列表进行静态分析。将 MUT与基本的模型相比较可以确定 2个图型之间的连贯性。
第八章 面向对象的软件测试
8.3.1分析和设计模型测试技术
6.“执行”测试用例。
7.使用测试用例覆盖率衡量法对测试的效率进行评价,计算覆率率百分比。比如,测试用例“涉及”到了包含 18个类的类图中的 12个类,那么测试的覆盖率就是 75%。鉴于分析和设计模型的测试如此高级,以至于要达到好的结果,
必须有 100%的覆盖率。
8.如果覆盖率不充分,就要对测试进行扩充并应用额外的测试用例。否则终止正在进行的测试。通常无法在检查片断的过程中写下附加的测试用例。测试者确定哪些地方没有覆盖到并与开发者一起确定将触及未覆盖的模型组件的潜在的测试用例。然后,测试者创建整个的测试用例并且进行另一次检查。
采用指导性审查技术对分析和设计产生的文本进行正确性验证,是软件开发前期的关键性测试。
第八章 面向对象的软件测试
8.3.2 类测试技术类测试与传统软件相比,面向对象程序的子过程 (方法 )
的结构趋于简单,而方法间的耦合程度却有了较大的提高,
交互过程也变得复杂,因此面向对象程序测试的重心就由对各独立过程进行的单元测试转移到了过程间的集成测试上,即测试的重点是类及类以上的各个层次。况且类是面向对象组成和运行的基本单元,对它的测试也就显得更加举足轻重。在对传统软件进行测试时,我们着眼的是程序的控制流或数据流。但对类进行测试时则必须考虑类的对象所具有的状态,着重考察一个对象接收到一个消息序列之后,是否达到了一个正确的状态。因此类测试的重点是类内方法间的交互和其对象的各个状态,类的测试用例主要是由方法序列集和相应的成员变量的取值所组成。
第八章 面向对象的软件测试
8.3.2 类测试技术类测试是由那些与验证类的实现是否和该类的说明完全一致的相关联的活动组成的。该类测试的对象主要是指能独立完成一定功能的原始类。如果类的实现正确,那么类的每一个实例的行为也应该是正确的。
因此,要求被测试的类有正确而且完整的描述,也就是说要求这个类在设计阶段产生的所有要素都是正确并且完整的。
类测试与传统的单元测试的过程却大体相似,不同之处在于传统单元测试注重单元之间的接口测试,也就是说每个单元都有自己的输入输出接口,在调用中如果出现严重错误,那么这些错误也是因为单元接口的实现引发的,和单元本身没有什么联系。但由于在类中内部封装了各种属性和消息传递方式,类实例化后产生的对象都有相对的生命周期和活动范围,类测试除了需要测试类中所包含的方法,还要测试类的状态,这是传统单元测试所没有的。
类是面向对象软件的核心,也是该类软件测试的重点和难点。因此有必要重点介绍一些针对类的测试方法。
第八章 面向对象的软件测试
8.3.2 类测试技术
1,类测试的内容类测试的目的主要是确保一个类的代码能够完全满足类的说明所描述的要求.对一个类进行测试以确保他只做规定的事情,对此给与关注的多少,取决于提供额外的行为的类相关联的风险.在运行了各种类的测试后,如果代码的覆盖率不完整,这可能意味着该类包含了额外的文档支持的行为.需要增加更多的测试用例来进行测试。
2,类测试的时间类测试的开始时间一般在完全说明这个类,并且准备对其编码后不久,就开发一个测试计划 —— 至少是确定测试用例的某种形式。如果开发人员还负责该类的测试,那么尤其应该如此。因为确定早期测试用例有利于开发人员理解类说明,也有助于获得独立代码检查的反馈。
第八章 面向对象的软件测试
8.3.2 类测试技术类测试可以在开发过程中的不同位臵进行。在递增的反复开发过程中,
一个类的说明和实现在一个工程的进程中可能会发生变化,所以因该在软件的其它部分使用该类之前执行类的测试。每当一个类的实现发生变化时,就应该执行回归测试。如果变化是因发现代码中的缺陷
( bug)而引起的,那么就必须执行测试计划的检查,而且必须增加或改变测试用例以测试在未来的测试期间可能出现的那些缺陷。
3,类测试的测试人员类测试通常由他的开发人员测试,让开发人员起到测试人员的作用,
就可使得必须理解类说明的人员数量减至最少。而且方便使用基于执行的测试方法,因为他们对代码极其的熟悉。由同一个开发者来测试,
也有一定的缺点:开发人员对类说明的任何错误理解,都会影响到测试。因此,最好要求另一个类的开发人员编写测试计划,并且允许对代码进行对立检查。这样就可以避免这些潜在的问题了。
第八章 面向对象的软件测试
8.3.2 类测试技术
4.基于状态的测试基于状态的测试以类的有限状态机模型 (FSM)和其状态转换图为依据,这种模型可以由软件的代码或规约生成,也可采用如 UML 的状态图。图 8-1 所示是一个堆栈类 Stack
() 的状态转换图,Stack 类共有三个状态,即 empty
(空 ),loaded (装载 ) 和 full (满 ),empty是初态,h是成员变量,表示栈的高度; max 是常量,表示栈的最大高度。图中箭头表示状态间的迁移,每一个迁移旁都有标注,,[ ]” 中的布尔表达式称为监视,它规定了该迁移发生所必须具备的条件,“?” 的左边是一个消息,一般是类中的方法 (如本例中的 push( x )入栈或 pop ()出栈 );
右边是程序作出的响应 (在本例中是返回栈顶值
return( x )或抛出异常 EmptyStackException 或
FullStackEx2ception),如图 8-7所示。
第八章 面向对象的软件测试
8.3.2 类测试技术图 8-7 Stack () 类的状态机模型第八章 面向对象的软件测试
8.3.2 类测试技术
5.基于方法序列的测试面向对象程序中方法的调用是有一定次序的,如果违反了这个次序就会产生错误。方法序列规范就是这样一种规范,
它规定了类中方法的执行顺序,如哪些方法必须按先后次序执行,哪些方法可以并发执行等等。依据这样的规约,
我们可以为类产生一些消息序列,检验这些类中的方法是否能够正确地交互。 并根据一定的准则对所产生的消息序列进行了划分,另外还采用颠倒次序、遗漏和冗余等方法由正确的消息序列生成错误的消息序列,以测试程序的健壮性。由于该方法没有能够考虑类的状态,因此采用它进行的测试是不完全的。这种方法常常与别的测试方法结合使用。
第八章 面向对象的软件测试
8.3.2 类测试技术
6.基于 UML 的测试
UML为面向对象软件提供了强大的建模工具,同时它也可以作为测试的依据。下面介绍的是几种已被应用于面向对象软件测试的 UML 模型,
类图类图描述了组成面向对象程序的各个类之间的关系,包括联系、聚集、重数、子类型和递归包含等。依据类图可以确定各个类之间的层次关系,从而决定对类进行测试的顺序。另外,采用类图可以生成检验类之间关系是否正确实现的测试用例。
顺序图顺序图描述对象之间动态的交互关系,着重体现对象间消息传递的时间顺序,因此它可以作为类簇测试的依据。顺序图可以转换为流程图,这种流程图表示了对象间消息传递的顺序,与程序流程图在形式上极为类似,也包括了顺序、分支和循环等。采用基本路径法可导出流程图的基本路径集,路径集中的每一条路径都是一个消息序列,
即测试用例。
状态图通常被用在基于状态的测试中。
用例图用例图一般被用在系统测试中,图中的每一个用例都可以转换为一个状态模型,然后参照状态测试的方法进行测试。
第八章 面向对象的软件测试
8.3.2 类测试技术
7.基于数据流的测试基于数据流的测试由传统的数据流测试发展而来,传统数据流测试的基本思想是,一个变量的定义,通过辗转的使用和定义,可以影响到另一个变量的值,或者影响到路径的选择等,因此,可以选择一定的测试数据,使程序按照一定的变量的定义 -使用路径执行,并检查执行结果是否与预期的相符,从而发现代码的错误。这种测试思想也适用于面向对象的软件。但在类级和类簇级测试中,由于方法执行的先后次序是动态决定的,因此必须首先得到类或类簇中的正确的方法序列,测试用例则围绕这些方法序列中的类成员变量的定义 -使用对产生。为一个类或类簇生成的测试用例集应能覆盖该类或类簇中所有类成员变量的定义 -使用对。该方法主要着眼于类或类簇中的数据流,
一般对其褒贬不一,有的认为这种测试是必不可少的,也有人认为这种方法破坏了类的封不值得提倡。
第八章 面向对象的软件测试
8.3.2 类测试技术
8.变异测试变异测试是一种基于错误的测试方法,它主要用于检测测试用例的有效性。其方法是在程序中植入一些错误,如将算术运算中的,+,变成,-,或,3,等,称为变异子 (m u tan t),如果测试用例能检测出这个变异子,就称它被“杀掉 (killed)” 了,如果植入的变异子不能被有效地杀掉,则说明测试用例不够,必须增加相应的测试用例。
传统的变异测试可直接用于方法测试中,但由于类和类簇等是传统程序所不具备的,所以必须为它们设计新的变异子。
9.基于使用的测试基于使用的测试是指在类或类簇的状态图或方法控制流图中加入有关使用的信息,即每一条路径的执行频率或其重要性,这些信息来自于系统的需求规范、设计者的经验、软件的应用环境以及类似程序的使用经验等。加入这些信息的目的是为了使测试者了解到程序的哪些部分使用的频率较高,以使之得到更为详尽的测试,另外应兼顾那些不是太常用但非常关键的路径,使其得到足够的测试。这种方法可以有效地指导测试用例的生成,并提高测试的效率。
第八章 面向对象的软件测试
8.3.2 类测试技术
10.测试程度可以根据已经测试了多少类实现和多少类说明来衡量测试的充分性。对于类的测试,通常需要将这两者都考虑到,
希望测试到操作和状态转换的各种组合情况。一个对象能维持自己的状态,而状态一般来说也会影响操作的含义。
但要穷举所有组合式不可能的,而且是没必要的 。因此,
就因该结合风险分析进行选择配对系列的组合,以致达到使用最重要的测试用例并抽取部分不太重要的测试用例。
11.类测试的范围
( 1)对认定的类的测试
OOD认定的类可以是 OOA中认定的对象,也可以是对象所需要的服务的抽象,对象所具有的属性的抽象。认定的类原则上应该尽量基础性,这样才便于维护和重用。
第八章 面向对象的软件测试
8.3.2 类测试技术
( 2)对构造的类层次结构的测试为能充分发挥面向对象的继承共享特性,OOD的类层次结构,通常基于 OOA中产生的分类结构的原则来组织,着重体现父类和子类间一般性和特殊性。两者概念上的差异。
在当前的问题空间,对类层次结构的主要要求是能在解空间构造实现全部功能的结构框架。为此,测试如下方面:
类层次结构是否含盖了所有定义的类;
是否能体现 OOA中所定义的实例关联;
是否能实现 OOA中所定义的消息关联;
子类是否具有父类没有的新特性;
子类间的共同特性是否完全在父类中得以体现。
第八章 面向对象的软件测试
8.3.2 类测试技术
( 3)对类库支持的测试对类库的支持虽然也属于类层次结构的组织问题,但其强调的重点是再次软件开发的重用。由于它并不直接影响当前软件的开发和功能实现,因此,将其单独提出来测试,
也可作为对高质量类层次结构的评估。参照 [9]中提出的准则,拟订测试点如下:
一组子类中关于某种含义相同或基本相同的操作,是否有相同的接口(包括名字和参数表);
类中方法( C++:类的成员函数)功能是否较单纯,相应的代码行是否较少( [5]中建议为不超过 30行);
类的层次结构是否是深度大,宽度小。
第八章 面向对象的软件测试
8.3.2 类测试技术
( 4)数据成员是否满足数据封装的要求数据封装是数据和数据有关的操作的集合。
检查数据成员是否满足数据封装的要求,
基本原则是数据成员是否被外界(数据成员所属的类或子类以外的调用)直接调用。
更直观的说,当改编数据成员的结构时,
是否影响了类的对外接口,是否会导致相应外界必须改动。值得注意,有时强制的类型转换会破坏数据的封装特性。例如:
第八章 面向对象的软件测试
8.3.2 类测试技术
class Hiden
{private:
int a=1;
char *p= "hiden";}
class Visible
{public:
int b=2;
char *s= "visible";}
..
..
Hiden pp;
Visible *qq=(Visible *)&pp;
在上面的程序段中,pp的数据成员可以通过 qq被随意访问。
第八章 面向对象的软件测试
8.3.2 类测试技术
( 5)类是否实现了要求的功能类所实现的功能,都是通过类的成员函数执行。在测试类的功能实现时,应该首先保证类成员函数的正确性。单独的看待类的成员函数,
与面向过程程序中的函数或过程没有本质的区别,几乎所有传统的单元测试中所使用的方法,都可在面向对象的单元测试中使用。具体的测试方法在面向对象的单元测试中介绍。类函数成员的正确行为只是类能够实现要求的功能的基础,类成员函数间的作用和类之间的服务调用是单元测试无法确定的。因此,需要进行面向对象的集成测试。
具体的测试方法在面向对象的集成测试中介绍。需要着重声明,测试类的功能,不能仅满足于代码能无错运行或被测试类能提供的功能无错,应该以所做的 OOD结果为依据,检测类提供的功能是否满足设计的要求,是否有缺陷。必要时(如通过 OOD结仍不清楚明确的地方)
还应该参照 OOA的结果,以之为最终标准。
第八章 面向对象的软件测试
8.3.2 类测试技术
①,如果函数(程序)对某一类输入中的一个数据正确执行,对同类中的其他输入也能正确执行。该假设的思想可参见 [6]中介绍的等价类划分。
②、如果函数(程序)对某一复杂度的输入正确执行,对更高复杂度的输入也能正确执行。例如需要选择字符串作为输入时,基于本假设,就无须计较于字符串的长度。除非字符串的长度是要求固定的,如 IP地址字符串。
在面向对象程序中,类成员函数通常都很小,功能单一,
函数的间调用频繁,容易出现一些不宜发现的错误。例如:
if (-1==write (fid,buffer,amount)) error_out();该语句没有全面检查 write()的返回值,无意中断然假设了只有数据被完全写入和没有写入两种情况。当测试也忽略了数据部分写入的情况,就给程序遗留了隐患。
第八章 面向对象的软件测试
8.3.2 类测试技术按程序的设计,使用函数 strrchr()查找最后的匹配字符,
但程序中写成了函数 strchr(),使程序功能实现时查找的是第一个匹配字符。程序中将 if
(strncmp(str1,str2,strlen(str1)))误写成了 if
(strncmp(str1,str2,strlen(str2)))。如果测试用例中使用的数据 str1和 str2长度一样,就无法检测出。
因此,在做测试分析和设计测试用例时,应该注意面向对象程序的这个特点,仔细的进行测试分析和设计测试用例,
尤其是针对以函数返回值作为条件判断选择,字符串操作等情况。
面向对象编程的特性使得对成员函数的测试,又不完全等同于传统的函数或过程测试。尤其是继承特性和多态特性,
使子类继承或过载的父类成员函数出现了传统测试中未遇见的问题。
第八章 面向对象的软件测试
8.3.3 类层次结构测试技术继承作为代码复用的一种机制,可能是面向对象软件开发产生巨大吸引力的一个重要因素。继承由扩展、覆盖和特例化三种基本机制实现的。其中,扩展是子类自动包含父类的特征;覆盖是子类中的方法与父类中的方法有相同的名字和消息参数以及相同的接口,但方法的实现不同;特例化是子类中特有的方法和实例变量。好的面向对象程序设计要求通过非常规范的方式使用继承 —— 即代码替代原则。在这种规则下,为一个类确定的测试用例集对该类的子类也是有效的。因此,
额外的测试用例通常应用于子类。通过仔细分析根据父类定义的子类的增量变化,有时候,子类中的某些部分可以不做执行测试。因为应用于父类中的测试用例所测试的代码被子类原封不动的继承,是同样的代码。
类的层次结构测试就是用来测试类的继承关系的技术,主要是用来测试层次关系的一系列类(包括父类和子类)。其测试的方法有用于测试子类的分层增量测试和用于测试父类的抽象类测试。
第八章 面向对象的软件测试
8.3.3 类层次结构测试技术分层、增量测试
C
D
Void op1 ( );
Void op2 ( );
Void op2 ( );
Void open ( );
Newvar type;
说明如下:
子类 D添加了一个新的实例变量( NewVar)和一个新的操作( newop( ))。
D重载了 C中定义的方法 op2(),因为该操作在 D中有新的规范或操作的实现。
分层增量测试( hierarchical incremental testing(HIT))指通过分析来确定子类的哪些测试用例需要添加,哪些继承的测试用例需要运行,以及哪些继承的测试用例不需要运行的测试方法。展示了 C类和它的派生类 D类,
以及它们之间的增量变化。 C类和它的派生类 D类间的增量变化能够用来帮助确定需要在 D中测试什么。
第八章 面向对象的软件测试
8.3.3 类层次结构测试技术由于 D类是 C类的子类,则所有用于 C类的基于规范的测试用例也都适用于 D类。那么,哪些继承的测试用例(用于子类的测试用例)适用于子类的测试,哪些又不必在子类中执行呢?要解决以上问题,可通过对子类的增量分析。
可能情况如下:
( 1) D的接口中添加一个或多个新的操作,并且有可能 D中的一个新方法实现一个新操作。新的操作引入了新的功能和新的代码,这些都需要测试。如果操作不是抽象的并且有具体的实现,那么为了合乎测试计划中的覆盖标准,需要添加基于规范和基于交互的测试用例。
( 2)通过两种方式改变由 C申明的操作的规范和实现:一,
在 D中改变那些在 D中申明的操作规范。二,在 D中覆盖那些在 C中实现了某个操作并且被 D继承了的方法。
第八章 面向对象的软件测试
8.3.3 类层次结构测试技术
( 3)在 D中添加一个或多个实例变量来实现更多的状态和属性。新添的变量最有可能与新的操作和重载方法中代码有关,而且对测试的处理也与他们有关。如果新的变量没有在任何地方使用,那么就不必做任何的变化。
( 4)在 D中改变类常量。类常量组成每个侧使用例的附加的后臵条件,
并且,“类常量句柄”在每个测试用例输出中是显示的。因此,如果类常量变化了,就需要重新运行所有继承的测试用例以验证常量句柄。
从基类派生出派生类时,不必为那些未经变化的操作添加基于规范的测试用例,测试用例能够不加修改的复用。如果测试的操作没有以任何方式加以修改,就不必运行这些测试用例中的任何一个。但是,如果一个操作的方法被间接的修改了,不但需要重新运行那些操作的任何一个测试用例,还需要运行附加的机遇实现的测试用例。
第八章 面向对象的软件测试
8.3.3 类层次结构测试技术
2.抽象类测试对类基于执行的测试时,需要建构一个类的实例。然而,一个继承体系的根类通常是抽象的,许多编程语言在语义上不允许建构抽象类的实例。这位抽象类的测试带来了很大的困难。在此,提出三种测试抽象类的方法:
( 1)需要测试的抽象类单独定义一个具体的子类。通过对具体子类创建的实例测试,来完成对抽象类的测试。这种方法的缺点是,如果不是用多层继承,抽象类的方法的实现就不能轻易的传递给抽象子类。但是大部分面向对象的编程语言都不支持多重继承,而且不提倡将多重继承用在这些方面。
( 2)将抽象类作为测试第一个具体子孙的一部分进行测试。这种方法不需要开发额外的用于测试的目的类,但需要考虑到为每一个祖先提供恰当的、
正确的测试用例和测试脚本方法,而增加了测试具体类的复杂性。
( 3)以对用于测试目的的抽象类的具体版本作直接实现,尝试找到一种为类编写源代码的方法,从而使得该类可以做为一个抽象或具体类而很容易编译。然而,不管是基于编辑遗产方案还是基于条件编译的方案都没有产生好的结果。应为合成代码都很复杂,而且难以阅读,很容易出错。
第八章 面向对象的软件测试
8.3.4 对象交互测试技术面向对象的软件是由若干对象组成的,通过这些对象的相续协作来解决某些问题。对象的交互和写作方式决定了程序能作什么,从而决定了这个程序执行的正确性。也许可信任的原始类的实例可能不包含任何错误,但是如果那个实例的服务部被其他程序组件正确的使用的话,那么这个程序也就包含了错误。因此,程序中对象的正确协作 ——
即交互 —— 对于程序的正确性是非常关键的。
对象的交互测试的重点是确保对象(这些对象的类已经被单独测试过)的消息传送能够正确进行。交互测试的执行可以使用嵌入到应用程序中的交互对象,或者在独立的测试工具(例如一个 Tester类)提供环境中,交互测试通过使得该环境中的对象相互交互而执行。
根据类的类型可以将对向交互测试分为汇集类测试和协作类测试。
第八章 面向对象的软件测试
8.3.4 对象交互测试技术汇集类测试汇集类指的是这样的一种类,这些类在他们的说明中使用对象,但是实际上从不和这些对象中的任何一个进行协作 —— 即他们从不请求这些对象的服务。相反,他们会表现出以下的一个或多个行为:
( 1)存放这些对象的引用(或指针),通常表现程序中的对象之间一对多的关系。
( 2)创建这些对象的实例。
( 3)删除这些对象的实例。
可以使用测试原始类的方法来测试汇集类,测试驱动程序要创建一些实例,
作为消息中的参数被传送给一个正在测试的集合。测试用例的中心目的主要是保证那些实例被正确加入集合和被正确的从集合中移出,以及测试用例说明的集合对其容量有所限制。因此,每个对象的准确的类(这些对象是用在汇集类的测试中)在确定汇集类的正确操作是不重要的,因为在一个集合实例和集合中的对象之间没有交互。假如在实际应用中可能要加入
40到 50条信息,那么生成的测试用例至少要增加 50条信息。如果无法估计出一个有代表性的上限,就必须使用集合中大量的对象进行测试。
第八章 面向对象的软件测试
8.3.4 对象交互测试技术如果汇集类不能为增加的新元素分配内存,就应该测试这个汇集类的行为,或者是可变数组这一结构,往往一次就为若干条信息分配空间。
在测试用例的执行期间,可以使用异常机制,帮助测试人员限制在测试用例执行期间可得到的内存容量的分配情况。如果已经使用了保护设计方法,那么,测试系列还应该包括否定系列。即当某些即和已拥有有限的制定容量,并且有实际的限制,则应该用超过指定的容量限制的测试用例进行测试。
3.协作类的测试凡不是汇集类的非原始类(原始累即一些简单的,独立的类,这些类可以用类测试方法进行测试)就是协作类。这种类在它们的一个或多个操作中使用其它的对象并将其作为他们的实现中不可缺少的一部分。
当接口中的一个操作的某个后臵条件引用了一个协作类的对象的实例状态,则说明那个对象的属性别使用或修改了。由此可见,协作类的测试的复杂性远远高于汇集类或者原始类测试的复杂性,鉴于协助类的测试需要根据具体的情况来定。
第八章 面向对象的软件测试
8.4 面向对象软件测试用例设计
OO测试用例设计包含 OO概念,在 OO度量中所讲的五个特性,局域性、封装性、信息隐藏、继承性和对象的抽象,肯定会对用例设计带来额外的麻烦和困难。 Berard提出了一些测试用例的设计方法,
主要原则包括,
1.每个测试用例应当给予特殊的标识,并且还应当与测试的类有明确的联系。
2.测试目的应当明确。
3.应当为每个测试用例开发一个测试步骤列表。
第八章 面向对象的软件测试
8.4 面向对象软件测试用例设计
8.4.1 基于故障的测试
8.4.2 基于脚本的测试
8.4.3 OO类的随机测试
8.4.4 类层次的分割测试
8.4.5 由行为模型(状态、活动、顺序和合作图)导出的测试
8.4.6 构建类测试用例第八章 面向对象的软件测试
8.4.1 基于故障的测试在 OO软件中,基于故障的测试具有较高的发现可能故障的能力。由于系统必须满足用户的需求,因此,基于故障的测试要从分析模型开始,
考察可能发生的故障。为了确定这些故障是否存在,可设计用例去执行设计或代码。
基于故障测试的关键取决于测试设计者如何理解“可能的错误”。而在实际中,要求设计者做到这点是不可能的。
基于故障测试也可以用于组装测试,组装测试可以发现消息联系中
“可能的故障”。,可能的故障”一般为意料之外的结果、错误地使用了操作 /消息、不正确引用等。为了确定由操作(功能)引起的可能故障必须检查操作的行为。
这种方法除用于操作测试外,还可用于属性测试,用以确定其对于不同类型的对象行为是否赋予了正确的属性值。因为一个对象的“属性”
是由其赋予属性的值定义的。
应当指出,组装测试是从客户对象(主动),而不是从服务器对象
(被动)上发现错误。正如传统的软件组装测试是把注意点集中在调用代码而不是被调用代码一样,即发现客户对象中“可能的故障”。
第八章 面向对象的软件测试
8.4.2 基于脚本的测试基于故障测试减少了两种主要类型的错误,一是不正确的规格说明,如做了用户不需要的功能,也可能缺少了用户需要的功能;二是子系统间的交互作用没有考虑,如一个子系统(事件或数据流等)的建立,导致其他子系统的失败。
基于脚本的测试主要关注用户需要做什么,而不是产品能做什么,即从用户任务(使用用例)中找出用户要做什么及去执行。
这种基于脚本的测试有助于在一个单元测试情况下检查多重系统。所以基于脚本测试用例测试比基于故障测试不仅更实际(接近用户),而且更复杂一点。
第八章 面向对象的软件测试
8.4.2 基于脚本的测试例如:考察一个文本编辑的基于脚本测试的用例设计。
使用用例:确定最终设计背景:打印最终设计,并能从屏幕图像上发现一些不易见到的且让人烦恼的错误。
其执行事件序列:打印整个文件;移动文件,修改某些页;当某页被修改,就打印某页;有时要打印许多页。
显然,测试者希望发现打印和编辑两个软件功能是否能够相互依赖,否则就会产生错误。
第八章 面向对象的软件测试
8.4.3 OO类的随机测试如果一个类有多个操作(功能),这些操作(功能)序列有多种排列。
而这种不变化的操作序列可随机产生,用这种可随机排列的序列来检查不同类实例的生存史,就叫随机测试。
例如一个银行信用卡的应用,其中有一个类:计算( account)。该
account的操作有,open,setup,deposit,withdraw,balance、
summarize,creditlimit和 close。
这些操作中的每一项都可用于计算,但 open,close必须在其他计算的任何一个操作前后执行,即使 open和 close有这种限制,这些操作仍有多种排列。所以一个不同变化的操作序列可由于应用不同而随机产生,如一个 Account实例的最小行为生存史可包括以下操作:
open+setup+deposit+[deposit|withdraw |balance|summarize|creditlimit]+withdraw+close 。
从此可见,尽管这个操作序列是最小测试序列,但在这个序列内仍可发生许多其他的行为。
第八章 面向对象的软件测试
8.4.4 类层次的分割测试这种测试可以减少用完全相同的方式检查类测试用例的数目。这很像传统软件测试中的等价类划分测试。分割测试又可分三种:
①基于状态的分割按类操作是否改变类的状态来分割(归类)。这里仍用 account类为例,改变状态的操作有 deposit,withdraw,不改变状态的操作有 balance、
summarize,creditlimit。如果测试按检查类操作是否改变类状态来设计,
则结果如下,
用例 1:执行操作改变状态
open+setup+deposit+deposit+withdraw+withdraw+close。
用例 2:执行操作不改变状态
open+setup+deposit+summarize+creditlimit+withdraw+close。
②基于属性的分割按类操作所用到的属性来分割(归类),如果仍以一个 account类为例,其属性 creditlimit能被分割为三种操作:用 creditlimit的操作,修改
creditlimit的操作,不用也不修改 creditlimit的操作。这样,测试序列就可按每种分割来设计。
③基于类型的分割按完成的功能分割。例如,在 account类的操作中,可以分割为:初始操作
open,setup;计算操作 deposit,withdraw;查询操作 balance,summarize、
creditlimit;终止操作 close。 第八章 面向对象的软件测试
8.4.5 由行为模型(状态、活动、顺序和合作图)导出的测试状态转换图( STD)可以用来帮助导出类的动态行为的测试序列,以及这些类与之合作的类的动态行为测试序列。
为了说明问题,仍用前面讨论过的 account类。开始由 empty acct状态转换为 setup acct状态。类实例的大多数行为发生在 working acct
状态中。而最后,取款和关闭分别使 account类转换到 non-working
acct和 dead acct状态。
这样,设计的测试用例应当是完成所有的状态转换。换句话说,操作序列应当能导致 account类所有允许的状态进行转换。
测试用例:
open+setupAcct+deposit(initial)+withdraw(final)+close 。
还可导出更多的测试用例,以保证该类所有行为被充分检查。
OO软件测试的主要目标与传统软件测试一样,即用最小量的投入来最大限度地发现软件存在的错误。但由于 OO软件具有的特殊性质,OO软件测试在内容、策略和方法上与传统软件测试不完全相同。
第八章 面向对象的软件测试
8.4.6 构建类测试用例要对类进行测试,就必须先确定和构建类的测试用例。类的描述方法有 OCL,自然语言,和状态图等方法,可以根据类说明的描述方法构件类的测试用例。因而,构建类的测试用例的方法有:根据类说明(用 OCL表示)确定测试用例和根据类的状态转换图来构建类的测试用例。
根据类的说明确定测试用例 用 OCL表示的类的说明中描述了类的每一个限定条件条件。在 OCL条件下分析每个逻辑关系,从而得到由这个条件的结构所对应的测试用例。
这种确定类的测试用例的方法叫做根据前臵条件和后臵条件构建测试用例。其总体思想是:为所有可能出现的组合情况确定测试用例需求。在这些可能出现的组合情况下,
可满足前臵条件,也能够到达后臵条件。根据这些需求,
创建测试用例;创建拥有特定输入值(常见值和特殊值)
的测试用例;确定它们的正确输出 —— 预期输出值。
第八章 面向对象的软件测试
8.4.6 构建类测试用例根据前臵条件和后臵条件创建测试用例的基本步骤如下:
( 1)确定在表 1中与前臵条件形成相匹配的各个项目所指定的一系列前臵条件的影响。
( 2)确定在表 2中与后臵条件形成相匹配的各个项目所指定的一系列前臵条件的影响。
( 3)根据影响到列表中各个项目的所有可能的组合情况从而构造测试用例需求。一种简单的方法就是:用第一个列表中的每一个输入约束来代替第二个列表中每一个前臵条件。
( 4)排除表中生成的所有无意义的条件。
第八章 面向对象的软件测试
8.4.6 构建类测试用例表 8-1 前置条件对测试系列的影响前臵条件 影 响
True (true,post)
A (A,post)(not A,exception) *
Not A (not A,post)(A,exception) *
A and B
(A and B,post)
(not A and B,exception) *
(A and not B,exception) *
(not A and not B,exception) *
A or B
(A,post)
(B,post)
(A and B,post)
(not A and not B,post)
A xor B
(not A and B,post)
(A and not B,post)
(A and B,exception) *
(not A and not B,exception) *
A implies B
(not A,post)
(B,post)
(not A and B,post)
(A and not B,exception) *
if A then B
else C endif
(A and B,post)
(not A and C,post)
(A and not B,exception) *
(not A and not C,exception) *第八章 面向对象的软件测试
8.4.6 构建类测试用例表 8-2 后置条件对测试系列的影响后臵条件 影 响
A (pre ; A)
A and B (pre ; A and B)
A or B
(pre ; A)
(pre ; B)
(pre ; A or B)
A xor B (pre ; not A or B)(pre ; A or not B)
A implies B (pre ; not A or B)
if A then B
else C endif
(pre and * ; B)
(pre and not * ; C)
第八章 面向对象的软件测试和根据前臵条件和后臵条件创建类的测试用例相比,根据状态转换图创建类的测试用例有非常大的优势。
8.5 面向对象测试基本步骤
8.5.1 单元测试
8.5.2 组装测试
8.5.3 确认测试第八章 面向对象的软件测试
8.5.1 单元测试面向对象测试计划完成以后,就可以进行单元测试了。与传统的单元
(模块)不同,OO中的单元是类。每个类都封装了属性(数据)和管理这些数据的操作。一 个类可以包含许多不同的操作,一个特殊的操作可以出现在许多不同的类中。
传统的单元测试只能测试一个操作(功能)。而在 OO单元测试中,一个操作功能只能作为一个类的一部分,类中有多个操作(功能),就要进行多个操作的测试。
另外,父类中定义的某个操作被许多子类继承。但在实际应用中,不同子类中某个操作在使用时又有细微的不同,所以还必须对每个子类中某个操作进行测试。
类的测试可以使用多种方法,如基于故障的测试、随机测试和分割测试等。每一种方法都要检查封装在类中的操作,即设计的测试序列
(用例),要保证相关的操作被检查。因为类的属性值表示类的状态,
由此来确定被检查的错误是否存在。
第八章 面向对象的软件测试
8.5.2 组装测试传统软件的层次模块间存在着控制关系,而 OO软件没有层次控制结构。所以传统的自顶向下和自底向上的组装策略在 OO软件组装测试中就没有意义了。
另外,一个类每次组装一个操作(传统软件的增量法)在 OO软件组装中是不够的,因为组成类的各个成分之间存在着直接或间接的交互作用。 OO软件的组装测试有两种不同的策略:
1.基于线程测试 (thread-based-testing)
基于线程的测试就是把合作对应一个输入或事件的类集合组装起来,也就是用响应系统的一个输入或一个事件的请求来组装类的集合。对每个线程都要分别进行组装和测试。
2.基于使用测试 (use-based-testing)
基于使用的测试就是按分层来组装系统,可以先进行独立类的测试。在独立类测试之后,下一个类的层次叫从属类。从属类用独立类进行测试。这种从属类层的顺序测试直到整个系统被构造完成。传统软件使用驱动程序和连接程序作为臵换操作,而 OO软件一般不用。
OO系统组装时还必须进行类间合作(强调上下级关系)的测试。类的合作测试与单个类测试相似,可用随机应用和分割测试来完成。还可以用基于脚本测试和行为模型导出的测试进行。
第八章 面向对象的软件测试
8.5.3 确认测试确认测试是在系统层进行测试,因此类间的联系细节出现了。与传统软件一样,OO
软件确认测试也主要集中在用户可见活动和用户可识别的系统输出上,所以 OO软件也使用传统软件的黑盒子测试方法。确认测试大多使用基于脚本( scenarios)的测试,因而使用用例成为确认测试的主要驱动器。
第八章 面向对象的软件测试
8.6 面向对象测试工具 JUnit
通过前面介绍,我们对面向对象测试有了一定了解,如果想提高面向对象测试的效率,那么应该选择一个合适与面向对象的测试工具,下面主要介绍用于测试由 java
语言编写的面向对象程序的测试工具 JUnit。
第八章 面向对象的软件测试
8.6 面向对象测试工具 JUnit
8.6.1 Junit简介
8.6.2 JUnit的安装和配臵
8.6.3 JUnit中常用的接口和类
8.6.4 用 Junit进行类测试实例第八章 面向对象的软件测试
8.6.1 Junit简介
JUnit是一个开源的 java单元测试框架。在 1997年,由 Erich Gamma
和 Kent Beck 开发完成。 Erich Gamma是 GOF 之一; Kent Beck 则在
XP 中有重要的贡献。点击 http://www.junit.org可以下载到最新版本的 Junit。
这样,在系统中就可以使用 JUnit编写单元测试代码了。
“麻雀虽小,五脏俱全。” JUnit设计的非常小巧,但是功能却非常强大。
下面是 JUnit一些特性的总结;
提供的 API可以让你写出测试结果明确的可重用单元测试用例;
提供了三种方式来显示你的测试结果,而且还可以扩展;
提供了单元测试用例成批运行的功能;
超轻量级而且使用简单,没有商业性的欺骗和无用的向导;
整个框架设计良好,易扩展。
对不同性质的被测对象,如 Class,Jsp,Servlet,Ejb等,Junit有不同的使用技巧。下面以类测试为例加以介绍。
第八章 面向对象的软件测试
8.6.2 JUnit的安装和配置
1.将下载的 Junit压缩包解压到一个物理目录中(例如 E:
\ Junit3.8.1)。
2.记录 Junit.jar文件所在目录名(例如 E:\
Junit3.8.1\Junit.jar)。
3.进入操作系统(以 Windows2000操作系统为例),按照次序点击“开始 → 设臵 → 控制面板”。在控制面板选项中选择“系统”,点击“环境变量”,在“系统变量”的“变量”列表框中选择,CLASS-PATH” 关键字(不区分大小写),如果该关键字不存在则添加。 双击,CLASS-PATH”
关键字添加字符串,E:\ Junit3.8.1\Junti.jar”( 注意,
如果已有别的字符串请在该字符串的字符结尾加上分号
“;” ),然后确定,Junit就可以在集成环境中应用了。
第八章 面向对象的软件测试
8.6.3 JUnit中常用的接口和类
1,Test接口(运行测试和收集测试结果 )
Test接口使用了 Composite设计模式,是单独测试用例 ( TestCase),聚合测试模式( TestSuite)及测试扩展( TestDecorator)的共同接口。它的
public int countTestCases()方法,它来统计这次测试有多少个 TestCase,
另外一个方法就是 public void run( TestResult ),TestResult是实例接受测试结果,run方法执行本次测试。
2,TestCase抽象类(定义测试中固定方法)
TestCase是 Test接口的抽象实现,(不能被实例化,只能被继承)其构造函数 TestCase(string name)根据输入的测试名称 name创建一个测试实例。由于每一个 TestCase在创建时都要有一个名称,若某测试失败了,便可识别出是哪个测试失败。
TestCase类中包含的 setUp(),tearDown()方法。 setUp()方法集中初始化测试所需的所有变量和实例,并且在依次调用测试类中的每个测试方法之前再次执行 setUp()方法。 tearDown()方法则是在每个测试方法之后,释放测试程序方法中引用的变量和实例。
开发人员编写测试用例时,只需继承 TestCase,来完成 run方法即可,然后
JUnit获得测试用例,执行它的 run方法,把测试结果记录在 TestResult之中。
第八章 面向对象的软件测试
8.6.3 JUnit中常用的接口和类
3,Assert静态类(系列断言方法的集合)
Assert包含了一组静态的测试方法,用于期望值和实际值比对是否正确,即测试失败,Assert类就会抛出一个 AssertionFailedError异常,JUnit测试框架将这种错误归入 Failes并加以记录,同时标志为未通过测试。如果该类方法中指定一个 String类型的传参则该参数将被做为 AssertionFailedError异常的标识信息,告诉测试人员改异常的详细信息。
JUnit 提供了 6大类 31组断言方法,包括基础断言、数字断言、字符断言、布尔断言、对象断言。
其中 assertEquals( Object expcted,Object actual)内部逻辑判断使用
equals()方法,这表明断言两个实例的内部哈希值是否相等时,最好使用该方法对相应类实例的值进行比较。而 assertSame( Object expected,Object
actual)内部逻辑判断使用了 Java运算符,==”,这表明该断言判断两个实例是否来自于同一个引用( Reference),最好使用该方法对不同类的实例的值进行比对。 asserEquals(String message,String expected,String
actual)该方法对两个字符串进行逻辑比对,如果不匹配则显示着两个字符串有差异的地方。 ComparisonFailure类提供两个字符串的比对,不匹配则给出详细的差异字符。
第八章 面向对象的软件测试
8.6.3 JUnit中常用的接口和类
4,TestSuite测试包类(多个测试的组合)
TestSuite类负责组装多个 Test Cases。待测得类中可能包括了对被测类的多个测试,而 TestSuit
负责收集这些测试,使我们可以在一个测试中,
完成全部的对被测类的多个测试。
TestSuite类实现了 Test接口,且可以包含其它的
TestSuites。它可以处理加入 Test时的所有抛出的异常。
TestSuite处理测试用例有 6个规约(否则会被拒绝执行测试)
第八章 面向对象的软件测试
8.6.3 JUnit中常用的接口和类
测试用例必须是公有类( Public);
测试用例必须继承与 TestCase类;
测试用例的测试方法必须是公有的
( Public );
测试用例的测试方法必须被声明为 Void;
测试用例中测试方法的前臵名词必须是
test;
测试用例中测试方法误任何传递参数。
第八章 面向对象的软件测试
8.6.3 JUnit中常用的接口和类
5,TestResult结果类和其它类与接口
TestResult结果类集合了任意测试累加结果,通过
TestResult实例传递个每个测试的 Run()方法。
TestResult在执行 TestCase时如果失败会异常抛出
TestListener接口是个事件监听规约,可供 TestRunner类使用。它通知 listener的对象相关事件,方法包括测试开始 startTest(Test test),测试结束 endTest(Test test),
错误,增加异常 addError(Test test,Throwable t)和增加失败 addFailure(Test test,AssertionFailedError
t),TestFailure失败类是个“失败”状况的收集类,解释每次测试执行过程中出现的异常情况。其 toString()方法返回“失败”状况的简要描述。
第八章 面向对象的软件测试
8.6.4 用 Junit进行类测试实例我们就以一个简单的例子入手。这是一个只会做两数加减的超级简单的计算器的 java类程序代码:
public class SampleCalculator
{
public int add(int augend,int addend)
{
return augend + addend;
}
public int subtration(int minuend,int subtrahend)
{
return minuend – subtrahend;
}
}
将上面的代码编译通过。下面就是为上面程序写的一个单元测试用例(请注意这个程序里面类名和方法名的特征):
第八章 面向对象的软件测试
8.6.4 用 Junit进行类测试实例
import junit.framework.TestCase;
public class TestSample extends TestCase
{
public void testAdd()
{
SampleCalculator calculator = new SampleCalculator();
int result = calculator.add(50,20);
assertEquals(70,result);
}
public void testSubtration();
{
SampleCalculator calculator = new SampleCalculator();
int result = calculator.subtration(50,20);
assertEquals(30,result);
}
}
第八章 面向对象的软件测试
8.6.4 用 Junit进行类测试实例然后在 DOS命令行里面输入 javac TestSample.java 将测试类编译通过。再输入 java junit.swingui.TestRunner
TestSample 运行测试类,将会看到测试结果,绿色说明单元测试通过,没有错误产生;如果是红色的,则就是说测试失败了。这样一个简单的单元测试就完成了。
按照框架规定:编写的所有测试类,必须继承自
junit.framework.TestCase类;里面的测试方法,命名应该以 Test开头,必须是 public void 而且不能有参数;而且为了测试查错方便,尽量一个 TestXXX方法对一个功能单一的方法进行测试;使用 assertEquals等
junit.framework.TestCase中的断言方法来判断测试结果正确与否。 经过简单的类测试学习,可以编写标准的类测试用例了。
第八章 面向对象的软件测试习题
1,名词解释,面向对象、消息、封装性、继承性、多态性、类测试。
2,简述面向对象的基本概念及特点。
3,面向对象测试与传统测试有哪些区别与联系?
4,简述面向对象测试步骤。
5,什么是类测试,主要方法是什么?
第八章 面向对象的软件测试
本章通过面向对象软件开发的特点引入了面向对象的软件测试,通过传统软件测试和面向对象软件测试的比较,分析了面向对象软件测试是软件测试行业发展的必然方向。进而又详细描述了面向对象软件测试的方法和策略。最后较为详细的阐述了类测试的概念和方法。
第八章 面向对象的软件测试
8.1 面向对象软件测试的基本概念
8.2 面向对象测试的内容与范围
8.3 面向对象软件测试技术与方法
8.4 面向对象软件测试用例设计
8.5 面向对象测试基本步骤
8.6 面向对象测试工具 JUnit
第八章 面向对象的软件测试
8.1 面向对象软件测试的基本概念面向对象方法( Object-Oriented Method)是一种把面向对象的思想应用于 软件开发 过程中,指导开发活动的系统方法,是建立在“对象”概念基础上的方法学。面向对象方法作为一种新型的独具优越性的新方法正在逐渐代替被广泛使用的面向过程开发方法,被看成是解决软件危机的新兴技术。面向对象技术产生更好的系统结构,更规范的编程风格,极大的优化了数据使用的安全性,提高了程序代码的重用,一些人就此认为面向对象技术开发出的程序无需进行测试。
第八章 面向对象的软件测试
8.1 面向对象软件测试的基本概念
8.1.1 面向对象软件设计的基本概念
8.1.2 面向对象软件开发过程及其特点
8.1.3 向对象软件测试的基本概念第八章 面向对象的软件测试
8.1.1 面向对象软件设计的基本概念
1.对象对象是要研究的任何事物。从一本书到一家图书馆,单的整数到整数列庞大的数据库、极其复杂的自动化工厂、航天飞机都可看作对象,
它不仅能表示有形的实体,也能表示无形的(抽象的)规则、计划或事件。对象由数据(描述事物的属性)和作用于数据的操作(体现事物的行为)构成一独立整体。从程序设计者来看,对象是一个程序模块,从用户来看,对象为他们提供所希望的行为。在对内的操作通常称为方法。
2.类类是对象的模板。即类是对一组有相同数据和相同操作的对象的定义,
一个类所包含的方法和数据描述一组对象的共同属性和行为。类是在对象之上的抽象,对象则是类的具体化,是类的实例。类可有其子类,
也可有其它类,形成类层次结构。
3.消息消息是对象之间进行通信的一种规格说明。一般它由三部分组成:接收消息的对象、消息名及实际变元。
第八章 面向对象的软件测试
8.1.1 面向对象软件设计的基本概念
4.封装性封装是一种信息隐蔽技术,它体现于类的说明,是对象的重要特性。封装使数据和加工该数据的方法(函数)封装为一个整体,以实现独立性很强的模块,使得用户只能见到对象的外特性(对象能接受哪些消息,具有那些处理能力),而对象的内特性
(保存内部状态的私有数据和实现加工能力的算法)对用户是隐蔽的。封装的目的在于把对象的设计者和对象者的使用分开,使用者不必知晓行为实现的细节,只须用设计者提供的消息来访问该对象。
5.继承性继承性是子类自动共享父类之间数据和方法的机制。它由类的派生功能体现。一个类直接继职其它类的全部描述,同时可修改和扩充。
6.多态性对象根据所接收的消息而做出动作。同一消息为不同的对象接受时可产生完全不同的行动,这种现象称为多态性。利用多态性用户可发送一个通用的信息,而将所有的实现细节都留给接受消息的对象自行决定,如是,同一消息即可调用不同的方法。例如:
Print消息被发送给一图或表时调用的打印方法与将同样的 Print消息发送给一正文文件而调用的打印方法会完全不同。多态性的实现受到继承性的支持,利用类继承的层次关系,把具有通用功能的协议存放在类层次中尽可能高的地方,而将实现这一功能的不同方法臵于较低层次,这样,在这些低层次上生成的对象就能给通用消息以不同的响应。在 OOPL中可通过在派生类中重定义基类函数(定义为重载函数或虚函数)来实现多态性。
第八章 面向对象的软件测试
8.1.2 面向对象软件开发过程及其特点面向对象的开发方法的基本思想认为,客观世界是由各种各样的对象组成的,每种对象都有各自的内部状态和运动规律,不同的对象之间的相互作用和联系就构成了各种不同的系统。故面向对象软件开发的工作过程为:
1.调查、分析系统需求,建立一个全面、合理、统一的模型。
2.在繁杂的问题域中抽象地识别出对象以及其行为、结构、属性、方法
3.对象设计 —— 即对分析的结果作进一步地抽象、归类、
整理,并最终以范式的形式将它们确定下来。
4.程序实现 —— 即用面向对象的程序设计语言将上一步整理的范式直接映射(直接用程序语言来取代)为应用程序软件。
第八章 面向对象的软件测试
8.1.2 面向对象软件开发过程及其特点面向对象开发的特点是遵循以下三项原则:
1.抽象原则( abstraction) —— 指为了某一分析目的而集中精力研究对象的某一性质,它可以忽略其它与此目的无关的部分
2.封装原则( encapsulation)即信息隐藏 ——
指在确定系统的某一部分内容时,应考虑到其它部分的信息及联系都在这一部分的内部进行,外部各部分之间的信息联系应尽可能的少。
3.继承原则( inheritance) —— 指能直接获得已有的性质和特征而不必重复定义它们。
第八章 面向对象的软件测试
8.1.3 向对象软件测试的基本概念
1,什么是面向对象的软件测试面向对象程序的结构不再是传统的功能模块结构,
作为一个整体,原有集成测试所要求的逐步将开发的模块搭建在一起进行测试的方法已成为不可能。而且,面向对象软件抛弃了传统的开发模式,
对每个开发阶段都有不同以往的要求和结果,已经不可能用功能细化的观点来检测面向对象分析和设计的结果。因此,传统的测试模型对面向对象软件已经不再适用。针对面向对象软件的开发特点,应该有一种新的测试模型。
第八章 面向对象的软件测试
8.1.3 向对象软件测试的基本概念
2.面向对象测试与传统测试的区别传统测试模式与面向对象的测试模式的最主要的区别在于,面向对象的测试更关注对象而不是完成输入 /输出的单一功能,这样的话测试可以在分析与设计阶段就先行介入,便得测试更好的配合软件生产过程并为之服务。与传统测试模式相比,面向对象测试的优点在于:更早地定义出测试用例;早期介入可以降低成本;尽早的编写系统测试用例以便于开发人员与测试人员对系统需求的理解保持一致;面向对象的测试模式更注重于软件的实质。具体有如下不同:
( 1)测试的对象不同:传统软件测试的对象是面向过程的软件,一般用结构化方法构建;面向对象测试的对象是面向对象软件,采用面向对象的概念和原则,用面向对象的方法构建。
( 2)测试的基本单位不同:前者是模块;面向对象测试的基本单元是类和对象。
( 3)测试的方法和策略不同:传统软件测试采用白盒测试,黑盒测试,路径覆盖等方法;面向对象测试不仅吸纳了传统测试方法,也采用各种类测试等方法,而且集成测试和系统测试的方法和策略也很不相同。
第八章 面向对象的软件测试
8.1.3 向对象软件测试的基本概念
3.面向对象测试模型 (Object-Orient Test Model)
现代的软件开发工程是将整个软件开发过程明确的划分为几个阶段,将复杂问题具体按阶段加以解决。这样,在软件的整个开发过程中,可以对每一阶段提出若干明确的监控点,作为各阶段目标实现的检验标准,从而提高开发过程的可见度和保证开发过程的正确性。实践证明软件的质量不仅是体现在程序的正确性上,它和编码以前所做的需求分析,软件设计也密切相关。这时,对错误的纠正往往不能通过可能会诱发更多错误的简单的修修补补,而必须追溯到软件开发的最初阶段。因此,为了保证软件的质量,
应该着眼于整个软件生存期,特别是着眼于编码以前的各开发阶段的工作。于是,软件测试的概念和实施范围必须扩充,应该包括在整个开发各阶段的复查、评估和检测。
由此,广义的软件测试实际是由确认、验证、测试三个方面组成。
第八章 面向对象的软件测试
8.1.3 向对象软件测试的基本概念确认:是评估将要开发的软件产品是否是正确无误、可行和有价值的。比如,将要开发的软件是否会满足用户提出的要求,是否能在将来的实际使用环境中正确稳定的运行,是否存在隐患等。这里包含了对用户需求满足程度的评价。确认意味着确保一个待开发软件是正确无误的,是对软件开发构想的检测。
验证:是检测软件开发的每个阶段、每个步骤的结果是否正确无误,
是否与软件开发各阶段的要求或期望的结果相一致。验证意味着确保软件是会正确无误的实现软件的需求,开发过程是沿着正确的方向在进行。
测试:与狭隘的测试概念统一。通常是经过单元测试、集成测试、系统测试三个环节。
在整个软件生存期,确认、验证、测试分别有其侧重的阶段。确认主要体现在计划阶段、需求分析阶段、也会出现在测试阶段;验证主要体现在设计阶段和编码阶段;测试主要体现在编码阶段和测试阶段。
事实上,确认、验证、测试是相辅相成的。确认无疑会产生验证和测试的标准,而验证和测试通常又会帮助完成一些确认,特别是在系统测试阶段。
第八章 面向对象的软件测试
8.1.3 向对象软件测试的基本概念和传统测试模型类似,面向对象软件的测试遵循在软件开发各过程中不间断测试的思想,使开发阶段的测试与编码完成后的一系列测试融为一体。在开发的每一阶段进行不同级别、不同类型的测试,从而形成一条完整的测试链。根据面向对象的开发模型,结合传统的测试步骤的划分,形成了一种整个软件开发过程中不断进行测试的测试模型,
使开发阶段的测试与编码完成后的单元测试、集成测试、系统测试成为一个整体。面向对象的开发模型突破了传统的瀑布模型,将开发分为面向对象分析( OOA),面向对象设计( OOD),和面向对象编程
( OOP)三个阶段。分析阶段产生整个问题空间的抽象描述,在此基础上,进一步归纳出适用于面向对象编程语言的类和类结构,最后形成代码。由于面向对象的特点,采用这种开发模型能有效的将分析设计的文本或图表代码化,不断适应用户需求的变动。针对这种开发模型,结合传统的测试步骤的划分,本文建议一种整个软件开发过程中不断测试的测试模型,使开发阶段的测试与编码完成后的单元测试、
集成测试、系统测试成为一个整体。测试模型如下图所示:
第八章 面向对象的软件测试
8.1.3 向对象软件测试的基本概念图 8-1 面向对象测试结构图
0 面向对象编程
OOA Test,面向对象分析的测试 OOD Test,面向对象设计的测试
OOP Test,面向对象编程的测试 OO Unit Test,面向对象单元测试
OO Integrate Test,面向对象集成测试 OO System Test,面向对象系统测试第八章 面向对象的软件测试
8.1.3 向对象软件测试的基本概念在面向对象软件测试中,OOA(面向对象分析)全面地将问题空间中实现的功能进行现实抽象化,将问题空间中的实例抽象为对象,用对象的结构反映问题空间的复杂关系,用属性和服务表示实例的特殊性和行为。 OOA的结果是为后面阶段类的选定和实现、类层次结构的组织和实现提供平台。其测试重点在于完整性和冗余性,包括对认定对象的测试、对认定结构的测试、对认定主题的测试、对定义的属性和实例关联的测试,对定义的服务和消息关联的测试。 OOD(面向对象设计)建立类结构或进一步构造类库,实现分析结果对问题空间的抽象。 OOD确定类和类结构不仅能够满足当前需求分析的要求,更主要的是通过重新组合或加以适当的补充,方便实现功能的重用和扩增。
包括测试认定的类、测试类层次结构(类的泛化继承和关联)和测试类库。 OOP(面向对象实施)是软件的计算机实现,根据面向对象软件的特性,可以忽略类功能实现的细节,将测试集中在类功能的实现和相应的面向对象程序风格即数据成员的封装性测试和类的功能性测试上。如果程序是用 C++等面向对象语言实现,主要就是对类成员函数的测试。
第八章 面向对象的软件测试
8.1.3 向对象软件测试的基本概念面向对象单元测试是进行面向对象集成测试的基础。面向对象集成测试主要对系统内部的相互服务进行测试,如成员函数间的相互作用,类间的消息传递等。面向对象集成测试不但要基于面向对象单元测试,更要参见 OOD或 OOD Test结果。面向对象系统测试是基于面向对象集成测试的最后阶段的测试,主要以用户需求为测试标准,需要借鉴 OOA或 OOA Test结果。
第八章 面向对象的软件测试
8.2 面向对象测试的内容与范围面向对象软件测试各阶段的测试构成一个相互作用的整体,但其测试的主体、方向和方法各有不同,本文接下来将从面向对象分析的测试,面向对象设计的测试,面向对象编程的测试,面向对象单元测试,
面向对象集成测试,面向对象系统测试六个方面分别介绍对面向对象软件的测试。
第八章 面向对象的软件测试
8.2 面向对象测试的内容与范围
8.2.1 面向对象分析的测试 (OOA Test)
8.2.2 面向对象设计的测试 (OOD Test)
8.2.3 面向对象编程的测试 (OOP Test)
8.2.4 面向对象的单元测试 (OO Unit Test)
8.2.5 面向对象的集成测试 (OO Integrate Test)
8.2.6 面向对象的系统测试 (OO System Test)
8.2.7 面向对象的其他测试第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
传统的面向过程分析是一个功能分解的过程,是把一个系统看成可以分解的功能的集合。这种传统的功能分解分析法的着眼点在于一个系统需要什么样的信息处理方法和过程,以过程的抽象来对待系统的需要。而面向对象分析( OOA)是 "把 E-R图和语义网络模型,即信息造型中的概念,与面向对象程序设计语言中的重要概念结合在一起而形成的分析方法 ",最后通常是得到问题空间的图表的形式描述。
OOA直接映射问题空间,全面的将问题空间中实现功能的现实抽象化。
将问题空间中的实例抽象为对象(不同于 C++中的对象概念),用对象的结构反映问题空间的复杂实例和复杂关系,用属性和服务表示实例的特性和行为。对一个系统而言,与传统分析方法产生的结果相反,
行为是相对稳定的,结构是相对不稳定的,这更充分反映了现实的特性。 OOA的结果是为后面阶段类的选定和实现,类层次结构的组织和实现提供平台。因此,OOA对问题空间分析抽象的不完整,最终会影响软件的功能实现,导致软件开发后期大量可避免的修补工作;而一些冗余的对象或结构会影响类的选定、程序的整体结构或增加程序员不必要的工作量。因此,本文对 OOA的测试重点在其完整性和冗余性。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
尽管 OOA的测试是一个不可分割的系统过程,
为叙述的方便,对 OOA阶段的测试划分为以下五个方面:
对确定类和对象的范围的测试
对确定结构范围的测试
对确定主题范围的测试
对确定属性和实例关联的测试
对确定服务和消息关联的测试第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
1.对确定类和对象的范围的测试确定类与对象就是在实际问题的分析中高度地抽象和封装能反映问题域和系统任务的特征的类和对象。对它的测试可以从如下方面考虑:
⑴ 抽象的对象是否全面,是否是现实问题空间中所有涉及到的实例都反映在认定的抽象对象中。
⑵ 抽象出的对象是否具有多个属性。只有一个属性的对象通常应看成其他对象的属性,而不是抽象为独立的对象。
⑶ 对抽象为同一对象的实例是否有共同的,区别于其他实例的共同属性。
⑷ 对抽象为同一对象的实例是否提供或需要相同的服务,如果服务随着不同的实例而变化,认定的对象就需要分解或利用继承性来分类表示。
(5) 抽象的对象的名称应该尽量准确,适用。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
如何在众多调查资料中进行分析并确定类与对象呢?解决这一问题的方法一般包含如下几个方面:
(1)基础素材。系统调查的所有图表、文件、说明以及分析人员的经验、学识都是 OOA分析的基础素材。
(2)潜在的对象。在对基础素材的分析中,哪种内容是潜在的,并且有可能被抽象地封装成对象与类呢?一般说来下列因素都是潜在的对象:结构、业务、系统、实体、应记忆的事件等。
(3)确定对象。 初步分析选定对象以后,就通过一个对象和其它对象之间关系的角度来进行检验,并最后确定它。
(4)图形表示。用图形化方法表示确定的对象和类。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
2.对确定结构范围的测试结构表示问题空间的复杂程度。标识结构的目的是便于管理问题域模型。在 OOA中,结构是指泛化-特化结构和整体-部分结构两部分的总和。
( 1)确定泛化-特化结构(分类结构)
泛化-特化结构有助于刻画出问题空间的类成员层次。继承的概念是泛化-特化结构的一个重要组成部分。继承提供了一个用于标识和表示公共属性与服务的显式方法。在一个泛化-特化结构内,继承使共享属性或共享服务、增加属性或增加服务成为可能。
定义泛化-特化结构时,要分析在问题空间和系统责任的范围内,通用类是否表达了专用类的共性,专用类是否表示了个性。
图 8-2给出的是泛化-特化结构。其中,“发表的文章”和“接受的文章”是特殊化类,“文章”是一般化类。特殊化类是一般化类的派生类,一般化类是特殊化类的基类。分类结构具有继承性,一般化类和对象的属性和服务一旦被识别,即可在特殊化类和对象中使用。文章发表的文章接受的文章第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
文章发表的文章 接受的文章图 8-2 泛化-特化结构图第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
( 2)确定整体-部分结构(组装结构)
整体-部分结构表示一个对象怎样作为别的对象的一部分,和对象怎样组成更大的对象,与我们在系统工程中划分子系统结构的思路基本一致。
图 8-3说明报社是由采访组、编辑室和印刷厂等几个部门组成,同时也指出,一个报社只有一个编辑室,一个印刷厂,但可以有一至多个采访组。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
1
报社采访组 编辑室 印刷厂
1
11,m 1
图 8-3整体-部分结构
1
分类结构体现了问题空间中实例的一般与特殊的关系,组装结构体现了问题空间中实例整体与局部的关系。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
( 3)从如下方面对认定的分类结构的测试。
自上而下的派生关系,对于结构中的一种对象,尤其是处于高层的对象,是否能派生出下一层对象。
自底向上的抽象关系:对于结构中的一种对象,尤其是处于同一底层的对象,是否能抽象出在现实中有意义的更一般的上层对象。
( 4)从如下方面对认定的组装结构的测试。
整体(对象)和部件(对象)的组装关系是否符合现实的关系。
整体(对象)的部件(对象)是否在考虑的问题空间中有实际应用。
整体(对象)中是否遗漏了反映在问题空间中有用的部件(对象)。
部件(对象)是否能够在问题空间中组装新的有现实意义的整体(对象)。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
3.对确定主题范围的测试在 OOA中主题是一种指导研究和处理大型复杂模型的机制。它有助于分解系统,
区别结构,避免过多的信息量同时出现所带来的麻烦。主题的确定可以帮助人们从一个更高的层次上来观察和表达系统的总体模型。
主题如同文章对各部分内容的概要。对主题层的测试应该考虑以下方面:
( 1) 贯彻 George Miller 的 "7+2"原则。即如果主题个数超过 7个,就要求对有较密切属性和服务的主题进行归并。
( 2)主题所反映的一组对象和结构是否具有相同和相近的属性和服务。
( 3)认定的主题是否是对象和结构更高层的抽象,是否便于理解 OOA结果的概貌(尤其是对非技术人员的 OOA 结果读者)。
( 4)主题间的消息联系(抽象)是否代表了主题所反映的对象和结构之间的所有关联。
在测试中,首先应该考虑:为每一个结构相应地增设一个主题;为每一个对象相应地增设一个主题。如果主题的个数过多,则需进一步精炼主题。根据需要,可以把紧耦合的主题合在一起抽象一个更高层次的模型概念供读者理解。然后,列出主题及主题层上各主题之间的消息连接。最后,对主题进行编号,在层次图上列出主题以指导读者从一个主题到另一个主题。每一层都组织成按主题划分的图。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
4.对确定属性和实例关联的测试在 OOA中属性被用来定义反映问题域的特点的任务。定义属性是通过确认信息和关系来完成的,它们和每个实例有关。对属性和实例关联的测试从如下方面考虑:
( 1)定义的属性是否对相应的对象和分类结构的每个现实实例都适用。
( 2)定义的属性在现实世界是否与这种实例关系密切。
( 3)定义的属性在问题空间是否与这种实例关系密切。
( 4)定义的属性是否能够不依赖于其他属性被独立理解。
( 5)定义的属性在分类结构中的位臵是否恰当,低层对象的共有属性是否在上层对象属性体现。
( 6)在问题空间中每个对象的属性是否定义完整。
( 7)定义的实例关联是否符合现实。
( 8)在问题空间中实例关联是否定义完整,特别需要注意一对多和多对多的实例关联。
具体方法如下:
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
① 确定属性的范围首先要确定划分给每一个对象的属性,明确某个属性究竟描述哪个对象,要保证最大稳定性和模型的一致性,其次,确定属性的层次,通用属性应放在结构的高层,特殊属性放在低层。如果一个属性适用于大多数的特殊分类,
可将其放在通用的地方,然后在不需要的地方把它覆盖(即用,X” 等记号指出不需要继承该属性),如果发现某个属性的值有时有意义,有时却不适用,
则应考虑分类结构,根据发现的属性,还可以进一步修订对象。
②实例连接实例连接是一个问题域的映射模型,该模型反映了某个对象对其它对象的需求。通过实例连接可以加强属性对类与状态的描述能力。
实例连接有一对一( 1,1)、一对多 (1,M)和多对多 (M,M)三种,分别表示一个实例可对应一个或多个实例,这种性质叫多重性。例如,一个车主拥有一辆汽车,则车主到汽车的实例连接是 1,1的;一个车主拥有多辆汽车,则是 1,M的。
实例连接的表示方法非常简单,只需在原类和对象的基础上用直线相连接,
并在直线的两端用数字标志出它们之间的上下限关系即可。例如在车辆和执照事故管理系统中,可以将车辆拥有者和法律事件两个类 &对象实例连接如图
8-4形式。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
1,m
m,1
owner person
telephone
legal event
registration date
图 8-4 车辆拥有者和法律事件的实例连接
③ 详细说明属性和实例连接的约束用名字和描述说明属性,属性可分成四类;描述性的、定义性的、
永远可导出的和偶而可导出的。实例连接的约束是指多重性与参与性。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
5.对确定服务和消息关联的测试对象收到消息后所能执行的操作称为它可提供的服务。它描述了系统需要执行的处理和功能。定义服务的目的在于定义对象的行为和对象之间的通信(消息连接)。事实上,两个对象之间可能存在着由于通信需要而形成的关系,即为消息连接。消息连接表示从一个对象发送消息到另一个对象,由那个对象完成某些处理。
确定服务的具体解决方法主要包括四个基本步骤:在分析中识别对象状态;识别所要求的服务;识别消息连接和指定服务。
( 1)识别对象状态在系统运行过程中,对象从被创建到释放要经历多种不同的状态。对象的状态是由属性的值来决定和表示的。一个对象状态是属性值的标识符,它反映了对象行为的改变。
识别对象状态的方法一般通过检查每一个属性的所有可能取值,确定系统的职责是否针对这些可能的值会有不同的行为;检查在相同或类似的问题论域中以前的分析结果,看是否有可直接复用的对象状态;
利用状态迁移图描述状态及其变化。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
( 2)识别所要求的服务必要的服务可分为两大类:简单的服务和复杂的服务。
简单的服务是每一个类或对象都应具备这样的服务,在分析模型中,
这些服务不必画出,如建立和初始化一个新对象,释放或删除一个对象等。
复杂的服务分为两种:计算服务和监控服务,必须在分析模型中显式地给出,计算服务是利用对象的属性值计算,以实现某种功能;监控服务主要处理对外部系统的输入 /输出,外部设备的控制和数据的存取。
为了标识必要的服务,需要注意检查每一个对象的所有状态,确定此对象在不同的状态值下要负责执行哪些计算、要做哪些监控,以便能够弄清外部系统或设备的状态将如何改变,对这些改变应当做什么响应;检查在相同或类似的问题论域中以前的分析结果,看是否有可直接复用的服务。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
( 3)识别消息连接消息连接是指从一个对象向另一个对象发送消息,并且使得某一处理功能,所需的处理是在发送对象的方法中指定的,并且在接收对象的方法中详细定义了的。
识别消息连接的方法及策略是检查在相同或类似的问题论域中以前分析的结果,看是否有可复用的消息连接。对于每一个对象,查询该对象需要哪些对象的服务,从该对象画一箭头到那个对象;查询哪个对象需要该对象的服务,从那个对象画一箭头到该对象;循消息连接找到下一个对象,重复以上步骤直至检查完全部对象。当一个对象将一个消息传送给另一个对象时,另一个对象又可传送一个消息给另一个对象,如此下去就可得到一条执行线索。检查所有的执行线索,确定哪些是关键执行线索,以检查模型的完备性。
( 4)定义服务在确定了对象的状态、所要执行的内容和消息后,具体如何执行操作呢? OOA提供了模板式的方法描述方式。这是一种类似程序框图的工具。它主要用定义方法和定义例示来实现。如图 8-5所示。
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
Specification
attribute 条件
… (if,precondition,trigger,terminate)
external input
external output 正文块
additional constraints (context)
notes
method(name & method chart) 循环
… (while,do,repeat,trrgger/terminate)
traceability codes
applicable store codes 连接
time requirements (connection)
图 8-5 定义方法和定义例示图 8-5 定义方法和定义例示
(b)(a)
第八章 面向对象的软件测试
8.2.1 面向对象分析的测试 (OOA Test)
对定义的服务和消息关联的测试从如下方面进行:
对象和结构在问题空间的不同状态是否定义了相应的服务。
对象或结构所需要的服务是否都定义了相应的消息关联。
定义的消息关联所指引的服务提供是否正确。
沿着消息关联执行的线程是否合理,是否符合现实过程。
定义的服务是否重复,是否定义了能够得到的服务。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
面向对象设计( OOD)是以 OOA为基础归纳出的类为基础,建立类结构甚至进一步构造成类库,实现了分析结果对问题空间的抽象。 OOD 归纳的类,可以是对象简单的延续,也可以是不同对象的相同或相似的服务。 OOD确定类和类结构不仅是满足当前需求分析的要求,更重要的是通过重新组合或加以适当的补充或删减,能方便实现功能的重用和扩增,以不断适应用户的要求。 OOD的基本目标是改进设计、增进软件生产效率、提高软件质量以及加强可维护性。如果模型的质量很高对项目来说就很有价值,但是如果模型有错误,那么它对项目的危害就无可估量。
以下面向对象设计模型是由 Coad和 Yourdon提出的。该模型由四个部分和五个层次组成。如下图 8-6所示。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
数据管理部件主题层结构层操作层服务层人机交互部件数据管理部件任务管理部件 类与对象层图 8-6 OOD系统模型其四个组成部分是问题空间部件 (Problem Domain Component,
简称 PDC)、人机交互部件 (Human Interaction Component,简称
HIC)、任务管理部件 (Task Management Component,简称 TMC)和数据管理部件 (Data Management Component,简称 DMC)。五个层次是主题层、类与对象层、结构层、属性层和服务层,这五个层次分别对应 Coad的面向对象分析方法中的确定对象、确定结构、定义主题、定义属性、确定服务等行动。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
所以,对 OOD的测试,建议从如下方面考虑:
确定测试的问题域。
人机交互部分设计的测试
对认定的类的测试。
对构造的类层次结构的测试。
对类库的支持的测试。
对测试结果以及对模型的测试覆盖率(基于某中标准)进行评估。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
1,确定测试的问题域在面向对象设计中,面向对象分析( OOA)的结果恰好符合面向对象设计( OOD)的问题空间部分,因此,OOA的结果就是 OOD部分模型中的一个完整部分。但是,为了解决一些特定设计所需要考虑的实际变化,可能要对 OOA结果进行一些改进和增补。主要是根据需求的变化,
对 OOA产生模型中的某些类与对象、结构、属性、操作进行组合与分解。要考虑对时间与空间的折衷、内存管理、开发人员的变更、以及类的调整等。另外,根据 OOD的附加原则,增加必要的类、属性和关系。
( 1)复用设计根据问题解决的需要,把从类库或其他来源得到的既存类增加到问题解决方案中去。既存类可以是用面向对象程序语言编写出来的,也可以是用其他语言编写出来的可用程序。要求标明既存类中不需要的属性和操作,把无用的部分维持到最小限度。并且增加从既存类到应用类之间的泛化-特化的关系。进一步地,把应用中因继承既存类而成为多余的属性和操作标出。还要修改应用类的结构和连接,必要时把它们变成可复用的既存类。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
( 2)把问题论域相关的类关联起来在设计时,从类库中引进一个根类,做为包容类,把所有与问题论域有关的类关联到一起,建立类的层次。把同一问题论域的一些类集合起来,存于类库中。
( 3)加入一般化类以建立类间协议有时,某些特殊类要求一组类似的服务。在这种情况下,应加入一个一般化的类,定义为所有这些特殊类共用的一组服务名,这些服务都是虚函数。在特殊类中定义其实现。
( 4)调整继承支持级别在 OOA阶段建立的对象模型中可能包括有多继承关系,但实现时使用的程序设计语言可能只有单继承,甚至没有继承机制,这样就需对分析的结果进行修改。可通过对把特殊类的对象看做是一个一般类对象所扮演的角色,通过实例连接把多继承的层次结构转换为单继承的层次结构;把多继承的层次结构平铺,成为单继承的层次结构等方法。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
( 5)改进性能提高执行效率和速度是系统设计的主要指标之一。有时,必须改变问题论域的结构以提高效率。如果类之间经常需要传送大量消息,可合并相关的类以减少消息传递引起的速度损失。增加某些属性到原来的类中,或增加低层的类,以保存暂时结果,避免每次都要重复计算造成速度损失。
( 6)加入较低层的构件在做面向对象分析时,分析员往往专注于较高层的类和对象,避免考虑太多低层的实现细节。但在做面向对象设计时,设计师在找出高层的类和对象时,
必须考虑到底需要用到哪些较低层的类和对象。
针对上述问题域的定义,制定如下测试策略:
首先制订检查的范围和深度。范围将通过描述材料的实体或一系列详细的用例来定义。对小的项目来说,范围可以是整个模型。深度将通过指定需要测试的模型( MUT)的某种 UML(统一建模语言)图的集合层次中的级别来定义。
然后为每一个评价标准开发测试用例,标准在应用时使用基本模型的内容作为输入。这种从用户用例模型出发的方式对许多模型的测试用例来说是一个很好的出发点。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
2.人机交互部分的设计( HIC)的测试通常在 OOA阶段给出了所需的属性和操作,在设计阶段必须根据需求把交互的细节加入到用户界面的设计中,包括有效的人机交互所必需的实际显式和输入。人机交互部分的设计决策影响到人的感情和精神感受,测试 HIC的策略由以下几方面构成:用户分类;描述人及其任务的脚本;设计命令层;设计详细的交互;继续做原型;设计 HIC类;
根据图形用户界面( GUI)进行设计。
( 1)用户分类进行用户分类的目的是明确使用对象,针对不同的使用对象设计不同的用户界面,以适合不同用户的需要。分类的原则有:
按技能层次分类:外行 /初学者 /熟练者 /专家;
按组织层次分类:行政人员 /管理人员 /专业技术人员 /其他办事员;
按职能分类:顾客 /职员。
( 2)描述人及其任务脚本对以上定义的每一类人,描述其身份、目的、特征、关键的成功因素、熟练程度及任务剧本。 第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
例 8-1 描述分析员:
什么人:分析员目的:要求一个工具来辅助分析工作(摆脱繁重的画图和检查图的工作)。
特点:年龄= 42岁;教育水平=大学;限制=不要微型打印。
成功的关键因素:工具应当使分析工作顺利进行;工具不应与分析工作冲突;
工具应能捕获假设和思想,能适时做出折衷;应能及时给出模型各个部分的文档,这与给出需求同等重要。
熟练程度:专家。
任务脚本:主脚本-识别“核心的”类和对象;识别“核心”结构;在发现了新的属性或操作时随时都可以加进模型中去。检验模型-打印模型及其全部文档。
( 3)设计命令层研究现行的人机交互活动的内容和准则,建立一个初始的命令层,再细化命令层:这时,要考虑:排列命令层次,把使用最频繁的操作放在前面,按照用户工作步骤排列;通过逐步分解,找到整体-部分模式,帮助在命令层中对操作进行分块;根据人们短期记忆的“”或“每次记忆 3块 /每块 3项”的特点,组织命令层中的服务,宽度与深度不宜太大,减少操作步骤。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
( 4)设计详细的交互用户界面设计有若干原则,一般有:一致性,操作步骤少,不要“哑播放”:即每当用户等待系统完成一个活动时,要给出一些反馈信息,
说明工作正在进展,以及进展的程度。:在操作出现错误时,要恢复或部分恢复原来的状态。提供联机的帮助信息。并具有趣味性,在外观和感受上,尽量采用图形界面,符合人类习惯,有一定吸引力。
( 5)继续做原型做人机交互原型是 HIC设计的基本工作,界面应使人花最少的时间去掌握其使用技法,做几个可候选的原型,让人们一个一个地试用,要达到“臻于完善”,由衷地满意。
( 6)设计 HIC类设计 HIC类,从组织窗口和部件地人机交互设计开始,窗口作基本类、
部件作属性或部分类。特殊窗口作特殊类。每个类包括窗口的菜单条、
下拉菜单、弹出菜单的定义,每个类还定义了用来创造菜单、加亮选择等所需的服务。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
( 7)根据 GUI(图形用户界面)进行设计图形用户界面区分为字型、坐标系统和事件。图形用户界面的字型是字体、字号、样式和颜色的组合。坐标系统主要因素有原点(基准点)、显式分辨率、显示维数等。事件则是图形用户界面程序的核心,
操作将对事件做出响应,这些事件可能是来自人的,也可能是来自其他操作的。事件的工作方式有两种:直接方式和排队方式。所谓直接方式,是指每个窗口中的项目有它自己的事件处理程序,一旦事件发生,则系统自动执行相应的事件处理程序。所谓排队方式,是指当事件发生时系统把它排到队列中,每个事件可用一些子程序信息来激发。
应用可利用,next event” 来得到一个事件并执行它所需要的一切活动。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
3.对任务管理部分设计( TMC)的测试在 OOD中,任务是指系统为了达到某一设定目标而进行的一连串的数据操作(或服务),若干任务的并发执行叫做多任务。任务能简化并发行为的设计和编码,TMC的设计就是针对任务项,对一连串的数据操作进行定义和封装,
对于多任务要确定任务协调部分,以达到系统在运行中对各项任务进行合理组织与管理。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
( 1) TMC设计策略
①识别事件驱动任务。事件驱动任务是指睡眠任务(不占用 CPU),当某个事件发生时,任务被此事件触发,任务醒来做相应处理,然后又回到睡眠状态。
②识别时钟驱动任务。按特定的时间间隔去触发任务进行处理,如某些设备需要周期性的数据采集和控制。
③识别优先任务和关键任务。把它们分离开来进行细致的设计和编码,
保证时间约束或安全性。
④识别协调者。增加一个任务来协调诸任务,这个任务可以封装任务之间的协作。
⑤审查每个任务,使任务数尽可能少。
⑥定义每个任务:包括任务名、驱动方式、触发该任务的事件、时间间隔、如何通信等。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
( 2)设计步骤
①对类和对象进行细化,建立系统的 OOA/OOD工作表格。 OOA/OOD工作表格包括:某系统可选定的对象的条目,对该对象在 OOD部件中位臵的说明和注释等。
②审查 OOA/OOD工作表格,寻找可能被封装在 TMC中那些与特定平台有关的部分以及任务协调部分、通信的从属关系、消息、线程序列等。
③构建新的类。 TM部件设计的首要任务就是构建一些新的类,这些类建立的主要目的是处理并发执行、中断、调度以及特定平台有关的一些问题。
任务管理部件一般在信息系统中使用较少,在控制系统中应用较多。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
4.对数据管理部分设计( DMC)的测试数据管理部分提供了在数据管理系统中存储和检索对象的基本结构,包括对永久性数据的访问和管理。它分离了数据管理机构所关心的事项,包括文件、关系型 DBMS或面向对象 DBMS等。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
( 1)数据管理方法数据管理方法主要有 3种:文件管理、关系数据库管理和面向对象库数据管理。
① 文件管理:提供基本的文件处理能力。
② 关系数据库管理系统( RDBMS):关系数据库管理系统建立在关系理论的基础上,它使用若干表格来管理数据,使用特定操作,如 select(提取某些行),project(提取某些栏),join(联结不同表格中的行,再提取某些行)
等,可对表格进行剪切和粘贴。通常根据规范化的要求,可对表格和它们的各栏重新组织,以减少数据冗余,保证修改一致性数据不致出错。
③ 面向对象数据库管理系统( OODBMS):通常,面向对象的数据库管理系统以两种方法实现:一是扩充的 RDBMS,二是扩充的面向对象程序设计语言
( OOPL)。
扩充的 RDBMS主要对 RDBMS扩充了抽象数据类型和继承性,再加上一些一般用途的操作来创建和操纵类与对象。扩充的 OOPL对面向对象程序设计语言嵌入了在数据库中长期管理存储对象的语法和功能。这样,可以统一管理程序中的数据结构和存储的数据结构,为用户提供了一个统一视图,无需在它们之间做数据转换。
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
( 2)数据管理部分的设计数据存储管理部分的设计包括数据存放方法的设计和相应操作的设计。
①数据存放设计数据存放有三种形式:文件存放方式、关系数据库存放方式和面向对象数据库存放方式,根据具体情况选用。
② 设计相应的操作为每个需要存储的对象及其类增加用于存储管理的属性和操作,在类及对象的定义中加以描述。通过定义,每个需要存储的对象将知道如何“存储我自己”。
为能充分发挥面向对象的继承共享特性,OOD的类层次结构,通常基于 OOA中产生的分类结构的原则来组织,着重体现父类和子类间一般性和特殊性。两者概念上的差异。在当前的问题空间,对类层次结构的主要要求是能在解空间构造实现全部功能的结构框架。为此,测试如下方面:
第八章 面向对象的软件测试
8.2.2 面向对象设计的测试 (OOD Test)
类层次结构是否含盖了所有定义的类;
是否能体现 OOA中所定义的实例关联;
是否能实现 OOA中所定义的消息关联;
子类是否具有父类没有的新特性;
子类间的共同特性是否完全在父类中得以体现。
第八章 面向对象的软件测试
8.2.3 面向对象编程的测试 (OOP Test)
典型的面向对象程序具有继承、封装和多态的新特性,这使得传统的测试策略必须有所改变。封装是对数据的隐藏,外界只能通过被提供的操作来访问或修改数据,这样降低了数据被任意修改和读写的可能性,降低了传统程序中对数据非法操作的测试。继承是面向对象程序的重要特点,继承使得代码的重用率提高,同时也使错误传播的概率提高。继承使得传统测试遇见了这样一个难题:对继承的代码究竟应该怎样测试?(参见面向对象单元测试)。多态使得面向对象程序对外呈现出强大的处理能力,但同时却使得程序内“同一”函数的行为复杂化,测试时不得不考虑不同类型具体执行的代码和产生的行为。
面向对象程序是把功能的实现分布在类中。能正确实现功能的类,通过消息传递来协同实现设计要求的功能。正是这种面向对象程序风格,
将出现的错误能精确的确定在某一具体的类。因此,在面向对象编程
( OOP)的测试中,忽略类功能实现的细则,将测试的目光集中在类功能的实现和相应的面向对象程序风格,主要体现为以下两个方面
(假设编程使用 C++语言)。
第八章 面向对象的软件测试
8.2.3 面向对象编程的测试 (OOP Test)
数据成员是否满足数据封装的要求类是否实现了要求的功能
1.数据成员是否满足数据封装的要求数据封装是数据和数据有关的操作的集合。检查数据成员是否满足数据封装的要求,基本原则是数据成员是否被外界(数据成员所属的类或子类以外的调用)直接调用。更直观的说,当改变数据成员的结构时,是否影响了类的对外接口,是否会导致相应外界必须改动。值得注意的是有时强制的类型转换会破坏数据的封装特性。
第八章 面向对象的软件测试
8.2.3 面向对象编程的测试 (OOP Test)
例 8-2:
class Hiden
{
private,
int a=1;
char *p= "hiden";
}
class Visible
{
public,
int b=2;
char *s= "visible";
}
.,
Hiden pp;
Visible *qq=(Visible *)&pp;
在上面的程序段中,pp的数据成员可以通过 qq被随意访问,这就破坏了数据的封装性。
第八章 面向对象的软件测试
8.2.3 面向对象编程的测试 (OOP Test)
2.类是否实现了要求的功能类所实现的功能,都是通过类的成员函数执行。在测试类的功能实现时,应该首先保证类成员函数的正确性。单独的看待类的成员函数,
与面向过程程序中的函数或过程没有本质的区别,几乎所有传统的单元测试中所使用的方法,都可在面向对象的单元测试中使用。具体的测试方法在面向对象的单元测试中介绍。类函数成员的正确行为只是类能够实现要求的功能的基础,类成员函数间的作用和类之间的服务调用是单元测试无法确定的。因此,需要进行面向对象的集成测试。
具体的测试方法在面向对象的集成测试中介绍。需要注意的是,测试类的功能,不能仅满足于代码能无错运行或被测试类能提供的功能无错,应该以所做的 OOD结果为依据,检测类提供的功能是否满足设计的要求,是否有缺陷。必要时(如通过 OOD结仍不清楚明确的地方)
还应该参照 OOA的结果,以之为最终标准。
第八章 面向对象的软件测试
8.2.4 面向对象的单元测试 (OO Unit Test)
传统的单元测试是针对程序的函数、过程或完成某一定功能的程序块。面向对象的单元测试对象是软件设计的最小单位 —— 类。单元测试的依据是详细设计,单元测试应对类中所有重要的属性和方法设计测试用例,以便发现类内部的错误。单元测试多采用白盒测试技术,系统内多个类块可以并行地进行测试。沿用单元测试的概念,实际测试类成员函数。一些传统的测试方法在面向对象的单元测试中都可以使用。如等价类划分法,因果图法,边值分析法,
逻辑覆盖法,路径分析法等等。
第八章 面向对象的软件测试
8.2.4 面向对象的单元测试 (OO Unit Test)
1.单元测试的内容面向对象的单元就是类,单元测试实际就是对类的测试。类测试的目的主要是确保一个类的代码能够完全满足类的说明所描述的要求。对一个类进行测试以确保它只做规定的事情,对此给与关注的多少,取决于提供额外的行为的类相关联的风险。每个类都封装了属性(数据)
和管理这些数据的操作(也被称做方法或服务)。一个类可以包含许多不同的操作,一个特殊的操作可以出现在许多不同的类中,而不是个体的模块。传统的单元测试只能测试一个操作(功能),而在面向对象单元测试中,一个操作功能只能作为一个类的一部分,类中有多个操作(功能),就要进行多个操作的测试。另外,父类中定义的某个操作被多个子类继承,不同子类中某个操作在使用时又有细微的不同,所以还必须对每个子类中某个操作进行测试。对类的测试强调对语句应该有 100%的执行代码覆盖率。在运行了各种类的测试用例后,
如果代码的覆盖率不完整,这可能意味着该类包含了额外的文档支持的行为,需要增加更多的测试用例来进行测试。
第八章 面向对象的软件测试
8.2.4 面向对象的单元测试 (OO Unit Test)
2.方法的测试在测试类的功能实现时,应该首先保证类成员函数的正确性。类函数成员的正确行为只是类能够实现要求的功能的基础,类成员函数间的作用和类之间的服务调用是单元测试无法确定的。因此,需要进行面向对象的集成测试。测试时主要考虑封装在类中的一个方法对数据进行的操作,可以采用传统的模块测试方法,但方法是封装在类中,并通过向所在对象发消息来执行,它的执行与状态有关,特别是在操作的多态性时,设计测试用例时要考虑设臵对象的初态,并且要设计一些函数来观察隐蔽的状态值。
类的行为是通过其内部方法来表现的,方法可以看作传统测试中的模块。因此传统针对模块的设计测试案例的技术,例如逻辑覆盖、等价划分、边界值分析和错误推测等方法,仍然可以作为测试类中每个方法的主要技术。面向对象中为了提高方法的重用性,每个方法所实现的功能应尽量小,每个方法常常只由几行代码组成,控制比较简单,因此测试用例的设计相对比较容易。
在传统的结构化系统中需要设计一个能调用被测模块的主程序来实现对模块的测试,而在面向对象系统中方法的执行是通过消息来驱动执行的,要测试类中的方法,必须用一个驱动程序对被测方法发一条消息以驱动其执行,如果被测模块或方法中有调用其它的模块或方法,则都需要设计一个模拟被调子程序功能的存根程序。驱动程序、存根程序及被测模块或方法组成一个独立的可执行的单元。
第八章 面向对象的软件测试
8.2.4 面向对象的单元测试 (OO Unit Test)
方法测试中有两个方面要加以注意。首先,方法执行的结果并不一定返回调用者,有的可能是改变被测对象的状态 (类中所有属性值 ) 。
状态是外界不可见的,为了测试对象状态的变化是否已经被执行,在驱动程序中还必须给对象发送一些额外的信息。其次,除了类中自己定义的方法,还可能存在从基类继承来的方法,这些方法虽然在基类中已经测试过,但派生类往往需要再次测试。
在面向对象软件中,在保证单个方法功能正确的基础上,还应该测试方法之间的协作关系。操作被封装在类中,对象彼此间通过发送消息启动相应的操作。但是,对象并没有明显地规定用什么次序启动它的操作才是合法的。这时,对象就像一个有多个入口的模块,因此,必须测试方法依不同次序组合的情况。但是为了提高方法的重用性,设计方法的一个准则是提高方法的内聚,即一个方法应该只完成单个功能,因此一个类中方法数一般较多。当类中方法数为 n时,全部的次序组合数为 2n。因此,测试完全的次序组合通常是不可能的,在设计测试用例时,同样可以利用等价划分、边界值、错误推测等技术从各种可能启动操作的次序组合中,选出最可能发现属性和操作错误的若干种情况,着重进行测试。测试步骤与单个方法测试步骤类似。
第八章 面向对象的软件测试
8.2.4 面向对象的单元测试 (OO Unit Test)
同样,对于继承来的方法与新方法的协作,也要加以测试。
因为随着新方法的加入,增加了启动操作次序的组合情况,
某些启动序列可能破坏对象的合法状态。所以,对于继承来的方法也需要仔细测试它们是否能够完成所要完成的功能。
由上述可见,如果以方法为单元进行测试,那么面向对象的单元测试就相当于归结为了传统的过程的单元测试了。
以前的方法都可以使用。
需要考虑的是,运行测试用例时候,必须提供能够实例化的桩类,以及起驱动器作用的“主程序”类,来提供和分析测试用例。
第八章 面向对象的软件测试
8.2.5 面向对象的集成测试 (OO Integrate Test)
传统的集成测试,是通过各种集成策略集成各功能模块进行测试,一般可以在部分程序编译完成的情况下进行。而对于面向对象程序,相互调用的功能是散布在程序的不同类中,类通过消息相互作用申请和提供服务。类的行为与它的状态密切相关,状态不仅仅是体现在类数据成员的值,也许还包括其他类中的状态信息。由此可见,类相互依赖极其紧密,根本无法在编译不完全的程序上对类进行测试。所以,
面向对象的集成测试通常需要在整个程序编译完成后进行。此外,面向对象程序具有动态特性,程序的控制流往往无法确定,因此也只能对整个编译后的程序做基于黑盒子的集成测试。
把一组相互有影响的类看作一个整体称为类簇。类簇测试主要根据系统中相关类的层次关系,检查类之间的相互作用的正确性,即检查各相关类之间消息连接的合法性、子类的继承性与父类的一致性、动态绑定执行的正确性、类簇协同完成系统功能的正确性等等。其测试有两种不同策略。
第八章 面向对象的软件测试
8.2.5 面向对象的集成测试 (OO Integrate Test)
1.基于类间协作关系的横向测试。
由系统的一个输入事件作为激励,对其触发的一组类进行测试,执行相应的操作 /消息处理路径,
最后终止于某一输出事件。应用回归测试对已测试过的类集再重新执行一次,以保证加入新类时不会产生意外的结果。
2.基于类间继承关系的纵向测试。
首先通过测试独立类 (是系统中已经测试正确的某类 )来开始构造系统,在独立类测试完成后,下一层继承独立类的类 (称为依赖类 ) 被测试,这个依赖类层次的测试序列一直循环执行到构造完整个系统。
第八章 面向对象的软件测试
8.2.5 面向对象的集成测试 (OO Integrate Test)
集成测试在面向对象系统中属于应用生命周期的一个阶段,可在两个层次上进行。第一层对一个新类进行测试,以及测试在定义中所涉及的那些类的集成。设计者通常用关系 is a,is part 和 refers to 来描述类与类之间的依赖,并隐含了类测试的顺序。首先测试基础类,
然后使用这些类的类接着测试,再按层次继续测试,每一层次都使用了以前已定义和测试过的类作为部件块。对于面向对象领域中集成测试的特别要求是:应当不需要特别地编写代码就可把在当前的软件开发中使用的元素集合起来。因此,其测试重点是各模块之间的协调性,
尤其是那些从没有在一起的类之间的协调性。
集成测试的第二层是将各部分集合在一起组成整个系统进行测试。以
C ++ 语言编写的应用系统为例,通常在其主程序中创建一些高层类和全局类的实例,通过这些实例的相互通讯从而实现系统的功能。对于这种测试所选择的测试用例应当瞄准待开发软件的目标而设计,并且应当给出预期的结果,以确定软件的开发是否与目标相吻合。
第八章 面向对象的软件测试
8.2.5 面向对象的集成测试 (OO Integrate Test)
面向对象的集成测试能够检测出相对独立的单元测试无法检测出的那些类相互作用时才会产生的错误。基于单元测试对成员函数行为正确性的保证,集成测试只关注于系统的结构和内部的相互作用。面向对象的集成测试可以分成两步进行:先进行静态测试,再进行动态测试。
静态测试主要针对程序的结构进行,检测程序结构是否符合设计要求。现在流行的一些测试软件都能提供一种称为 "可逆性工程 "的功能,即通过原程序得到类关系图和函数功能调用关系图,例如 International Software
Automation 公司的 Panorama-2 forWindows95,Rational公司的 Rose C++
Analyzer等,将 "可逆性工程 "得到的结果与 OOD的结果相比较,检测程序结构和实现上是否有缺陷。换句话说,通过这种方法检测 OOP是否达到了设计要求。
动态测试设计测试用例时,通常需要上述的功能调用结构图、类关系图或者实体关系图为参考,确定不需要被重复测试的部分,从而优化测试用例,减少测试工作量,使得进行的测试能够达到一定覆盖标准。测试所要达到的覆盖标准可以是:达到类所有的服务要求或服务提供的一定覆盖率;依据类间传递的消息,达到对所有执行线程的一定覆盖率;达到类的所有状态的一定覆盖率等。同时也可以考虑使用现有的一些测试工具来得到程序代码执行的覆盖率。
第八章 面向对象的软件测试
8.2.5 面向对象的集成测试 (OO Integrate Test)
具体设计测试用例,可参考下列步骤:
( 1) 先选定检测的类,参考 OOD分析结果,仔细出类的状态和相应的行为,类或成员函数间传递的消息,输入或输出的界定等。
( 2)确定覆盖标准。
( 3)利用结构关系图确定待测类的所有关联。
( 4)根据程序中类的对象构造测试用例,确认使用什么输入激发类的状态、使用类的服务和期望产生什么行为等。
值得注意,设计测试用例时,不但要设计确认类功能满足的输入,还应该有意识的设计一些被禁止的例子,确认类是否有不合法的行为产生,如发送与类状态不相适应的消息,要求不相适应的服务等。根据具体情况,动态的集成测试,有时也可以通过系统测试完成。
第八章 面向对象的软件测试
8.2.6 面向对象的系统测试 (OO System Test)
系统测试应该尽量搭建与用户实际使用环境相同的测试平台,应该保证被测系统的完整性,对临时没有的系统设备部件,也应有相应的模拟手段。系统测试时,应该参考
OOA分析的结果,对应描述的对象、属性和各种服务,检测软件是否能够完全 "再现 "问题空间。系统测试不仅是检测软件的整体行为表现,从另一个侧面看,也是对软件开发设计的再确认。
这里说的系统测试是对测试步骤的抽象描述。它体现的具体测试内容包括:
第八章 面向对象的软件测试
8.2.6 面向对象的系统测试 (OO System Test)
1.功能测试测试是否满足开发要求,是否能够提供设计所描述的功能,是否用户的需求都得到满足。功能测试是系统测试最常用和必须的测试,通常还会以正式的软件说明书为测试标准。
2.强度测试测试系统的能力最高实际限度,即软件在一些超负荷的情况,功能实现情况。如要求软件某一行为的大量重复、输入大量的数据或大数值数据、对数据库大量复杂的查询等。
3.性能测试测试软件的运行性能。这种测试常常与强度测试结合进行,需要事先对被测软件提出性能指标,如传输连接的最长时限、传输的错误率、
计算的精度、记录的精度、响应的时限和恢复时限等。
4.安全测试验证安装在系统内的保护机构确实能够对系统进行保护,使之不受各种非常的干扰。安全测试时需要设计一些测试用例试图突破系统的安全保密措施,检验系统是否有安全保密的漏洞。
第八章 面向对象的软件测试
8.2.6 面向对象的系统测试 (OO System Test)
5.恢复测试采用人工的干扰使软件出错,中断使用,检测系统的恢复能力,特别是通讯系统。恢复测试时,应该参考性能测试的相关测试指标。
可用性测试:测试用户是否能够满意使用。具体体现为操作是否方便,用户界面是否友好等。
6.安装 /卸载测试测试用户能否方便地安装 /卸载软件。
系统测试需要对被测的软件结合需求分析做仔细的测试分析,建立测试用例。
7.可用性测试:测试用户是否能够满意使用。具体体现为操作是否方便,用户界面是否友好等。
8.基于 UML的系统测试第八章 面向对象的软件测试
8.2.6 面向对象的系统测试 (OO System Test)
考查系统的规格说明,用例图,GUI状态图。分成下面四个层次:
( 1)构建用例与系统功能的关联矩阵,建立测试覆盖的初步标准,从对应于扩展基本用例的真实用例中导出测试用例。
( 2)通过所有真实用例开发测试用例。
( 3)用过有限状态机导出测试用例,有限状态机有 GUI外观有限状态机描述导出。
( 4)通过基于状态的事件表导出测试用例,这种工作必须对每个状态重复进行。
第八章 面向对象的软件测试
8.2.6 面向对象的系统测试 (OO System Test)
9.基于状态图的系统测试状态图是系统测试的很好的基础。问题是,UML将状态图规定为类级的。合成多个类的状态图得到一个系统级的状态图是很难的。一种可行的方法是,将每个类级的状态图转换成一组 EDPN,然后合成 EDPN。
第八章 面向对象的软件测试
8.2.7 面向对象的其他测试在面向对象测试中,除需要进行上面介绍的测试外,还应该进行如下测试。
1.基于故障的测试
2.基于脚本的测试
3.面向对象类的随机测试
4.类层次的分割测试第八章 面向对象的软件测试
8.3 面向对象软件测试技术与方法面向对象方法的使用日益普及,随之而来的面向对象软件的质量问题也越来越受到人们的重视。软件测试是提高软件质量的重要途径。但与面向对象软件的开发技术相比,面向对象软件的测试技术却仍处于初级阶段。
第八章 面向对象的软件测试
8.3 面向对象软件测试技术与方法
8.3.1分析和设计模型测试技术
8.3.2 类测试技术
8.3.3 类层次结构测试技术
8.3.4 对象交互测试技术第八章 面向对象的软件测试
8.3.1分析和设计模型测试技术面向对象软件开发的起始步骤是开发分析和设计模型。
UML(统一建模语言)能在面向对象技术开发中广泛应用,
也是因为构建模型能帮助开发者理解正在解决的问题;构建模型能帮助管理正在开发的系统的复杂性;分析和设计阶段建构的模型最后将对具体地实现起指导作用。如果模型的质量很高对项目来说就很有价值;但是如果模型有错误,那么它对项目的危害就无可估量。
分析与设计模型的测试主要是对分析与设计模型进行测试,
找出模型中的错误,其采用的方法是指导性审查 (guided
inspection)。指导性审查技术通过使用明确的测试用例为查找工作成果中的缺陷提供了客观的、系统的方法。是一种增强了的专为检验模型的检测技巧,也可用来验证模型是否能符合项目的需求。其基本步骤如下:
第八章 面向对象的软件测试
8.3.1分析和设计模型测试技术
定义测试位臵。
使用特定的策略从测试位臵选择测试值。
将测试值应用到被测试的产品中。
对测试结果以及对模型的测试覆盖率(基于某中标准)进行评估。
第八章 面向对象的软件测试
8.3.1分析和设计模型测试技术这些步骤经过具体化后形成下列详细步骤:
1.制订检查的范围和深度:范围将通过描述材料的实体或一系列详细的用例来定义。对小的项目来说,范围可以是整个模型。深度将通过指定须要测试的模型( MUT)的某种 UML图的集合层次中的级别来定义。
2.确定 MUT产生的基础:除原始模型之外,所有的 UMT的基础是前一开发阶段创建的一系列模型:比如,应用分析模型就是以域分析模型和用例模型为基础。起初模型则是基于所选择的一组人头脑里的知识。
3.为每一个评价标准开发测试用例,标准在应用时使用基本模型的内容作为输入。这种从用户用例模型出发的方式对许多模型的测试用例来说是一个很好的出发点。
4.为测量测试的覆盖率建立标准。比如对一个类图来说,如果图中每一个类都被测试到了,那么覆盖率就算不错了。
5.使用合适的检查列表进行静态分析。将 MUT与基本的模型相比较可以确定 2个图型之间的连贯性。
第八章 面向对象的软件测试
8.3.1分析和设计模型测试技术
6.“执行”测试用例。
7.使用测试用例覆盖率衡量法对测试的效率进行评价,计算覆率率百分比。比如,测试用例“涉及”到了包含 18个类的类图中的 12个类,那么测试的覆盖率就是 75%。鉴于分析和设计模型的测试如此高级,以至于要达到好的结果,
必须有 100%的覆盖率。
8.如果覆盖率不充分,就要对测试进行扩充并应用额外的测试用例。否则终止正在进行的测试。通常无法在检查片断的过程中写下附加的测试用例。测试者确定哪些地方没有覆盖到并与开发者一起确定将触及未覆盖的模型组件的潜在的测试用例。然后,测试者创建整个的测试用例并且进行另一次检查。
采用指导性审查技术对分析和设计产生的文本进行正确性验证,是软件开发前期的关键性测试。
第八章 面向对象的软件测试
8.3.2 类测试技术类测试与传统软件相比,面向对象程序的子过程 (方法 )
的结构趋于简单,而方法间的耦合程度却有了较大的提高,
交互过程也变得复杂,因此面向对象程序测试的重心就由对各独立过程进行的单元测试转移到了过程间的集成测试上,即测试的重点是类及类以上的各个层次。况且类是面向对象组成和运行的基本单元,对它的测试也就显得更加举足轻重。在对传统软件进行测试时,我们着眼的是程序的控制流或数据流。但对类进行测试时则必须考虑类的对象所具有的状态,着重考察一个对象接收到一个消息序列之后,是否达到了一个正确的状态。因此类测试的重点是类内方法间的交互和其对象的各个状态,类的测试用例主要是由方法序列集和相应的成员变量的取值所组成。
第八章 面向对象的软件测试
8.3.2 类测试技术类测试是由那些与验证类的实现是否和该类的说明完全一致的相关联的活动组成的。该类测试的对象主要是指能独立完成一定功能的原始类。如果类的实现正确,那么类的每一个实例的行为也应该是正确的。
因此,要求被测试的类有正确而且完整的描述,也就是说要求这个类在设计阶段产生的所有要素都是正确并且完整的。
类测试与传统的单元测试的过程却大体相似,不同之处在于传统单元测试注重单元之间的接口测试,也就是说每个单元都有自己的输入输出接口,在调用中如果出现严重错误,那么这些错误也是因为单元接口的实现引发的,和单元本身没有什么联系。但由于在类中内部封装了各种属性和消息传递方式,类实例化后产生的对象都有相对的生命周期和活动范围,类测试除了需要测试类中所包含的方法,还要测试类的状态,这是传统单元测试所没有的。
类是面向对象软件的核心,也是该类软件测试的重点和难点。因此有必要重点介绍一些针对类的测试方法。
第八章 面向对象的软件测试
8.3.2 类测试技术
1,类测试的内容类测试的目的主要是确保一个类的代码能够完全满足类的说明所描述的要求.对一个类进行测试以确保他只做规定的事情,对此给与关注的多少,取决于提供额外的行为的类相关联的风险.在运行了各种类的测试后,如果代码的覆盖率不完整,这可能意味着该类包含了额外的文档支持的行为.需要增加更多的测试用例来进行测试。
2,类测试的时间类测试的开始时间一般在完全说明这个类,并且准备对其编码后不久,就开发一个测试计划 —— 至少是确定测试用例的某种形式。如果开发人员还负责该类的测试,那么尤其应该如此。因为确定早期测试用例有利于开发人员理解类说明,也有助于获得独立代码检查的反馈。
第八章 面向对象的软件测试
8.3.2 类测试技术类测试可以在开发过程中的不同位臵进行。在递增的反复开发过程中,
一个类的说明和实现在一个工程的进程中可能会发生变化,所以因该在软件的其它部分使用该类之前执行类的测试。每当一个类的实现发生变化时,就应该执行回归测试。如果变化是因发现代码中的缺陷
( bug)而引起的,那么就必须执行测试计划的检查,而且必须增加或改变测试用例以测试在未来的测试期间可能出现的那些缺陷。
3,类测试的测试人员类测试通常由他的开发人员测试,让开发人员起到测试人员的作用,
就可使得必须理解类说明的人员数量减至最少。而且方便使用基于执行的测试方法,因为他们对代码极其的熟悉。由同一个开发者来测试,
也有一定的缺点:开发人员对类说明的任何错误理解,都会影响到测试。因此,最好要求另一个类的开发人员编写测试计划,并且允许对代码进行对立检查。这样就可以避免这些潜在的问题了。
第八章 面向对象的软件测试
8.3.2 类测试技术
4.基于状态的测试基于状态的测试以类的有限状态机模型 (FSM)和其状态转换图为依据,这种模型可以由软件的代码或规约生成,也可采用如 UML 的状态图。图 8-1 所示是一个堆栈类 Stack
() 的状态转换图,Stack 类共有三个状态,即 empty
(空 ),loaded (装载 ) 和 full (满 ),empty是初态,h是成员变量,表示栈的高度; max 是常量,表示栈的最大高度。图中箭头表示状态间的迁移,每一个迁移旁都有标注,,[ ]” 中的布尔表达式称为监视,它规定了该迁移发生所必须具备的条件,“?” 的左边是一个消息,一般是类中的方法 (如本例中的 push( x )入栈或 pop ()出栈 );
右边是程序作出的响应 (在本例中是返回栈顶值
return( x )或抛出异常 EmptyStackException 或
FullStackEx2ception),如图 8-7所示。
第八章 面向对象的软件测试
8.3.2 类测试技术图 8-7 Stack () 类的状态机模型第八章 面向对象的软件测试
8.3.2 类测试技术
5.基于方法序列的测试面向对象程序中方法的调用是有一定次序的,如果违反了这个次序就会产生错误。方法序列规范就是这样一种规范,
它规定了类中方法的执行顺序,如哪些方法必须按先后次序执行,哪些方法可以并发执行等等。依据这样的规约,
我们可以为类产生一些消息序列,检验这些类中的方法是否能够正确地交互。 并根据一定的准则对所产生的消息序列进行了划分,另外还采用颠倒次序、遗漏和冗余等方法由正确的消息序列生成错误的消息序列,以测试程序的健壮性。由于该方法没有能够考虑类的状态,因此采用它进行的测试是不完全的。这种方法常常与别的测试方法结合使用。
第八章 面向对象的软件测试
8.3.2 类测试技术
6.基于 UML 的测试
UML为面向对象软件提供了强大的建模工具,同时它也可以作为测试的依据。下面介绍的是几种已被应用于面向对象软件测试的 UML 模型,
类图类图描述了组成面向对象程序的各个类之间的关系,包括联系、聚集、重数、子类型和递归包含等。依据类图可以确定各个类之间的层次关系,从而决定对类进行测试的顺序。另外,采用类图可以生成检验类之间关系是否正确实现的测试用例。
顺序图顺序图描述对象之间动态的交互关系,着重体现对象间消息传递的时间顺序,因此它可以作为类簇测试的依据。顺序图可以转换为流程图,这种流程图表示了对象间消息传递的顺序,与程序流程图在形式上极为类似,也包括了顺序、分支和循环等。采用基本路径法可导出流程图的基本路径集,路径集中的每一条路径都是一个消息序列,
即测试用例。
状态图通常被用在基于状态的测试中。
用例图用例图一般被用在系统测试中,图中的每一个用例都可以转换为一个状态模型,然后参照状态测试的方法进行测试。
第八章 面向对象的软件测试
8.3.2 类测试技术
7.基于数据流的测试基于数据流的测试由传统的数据流测试发展而来,传统数据流测试的基本思想是,一个变量的定义,通过辗转的使用和定义,可以影响到另一个变量的值,或者影响到路径的选择等,因此,可以选择一定的测试数据,使程序按照一定的变量的定义 -使用路径执行,并检查执行结果是否与预期的相符,从而发现代码的错误。这种测试思想也适用于面向对象的软件。但在类级和类簇级测试中,由于方法执行的先后次序是动态决定的,因此必须首先得到类或类簇中的正确的方法序列,测试用例则围绕这些方法序列中的类成员变量的定义 -使用对产生。为一个类或类簇生成的测试用例集应能覆盖该类或类簇中所有类成员变量的定义 -使用对。该方法主要着眼于类或类簇中的数据流,
一般对其褒贬不一,有的认为这种测试是必不可少的,也有人认为这种方法破坏了类的封不值得提倡。
第八章 面向对象的软件测试
8.3.2 类测试技术
8.变异测试变异测试是一种基于错误的测试方法,它主要用于检测测试用例的有效性。其方法是在程序中植入一些错误,如将算术运算中的,+,变成,-,或,3,等,称为变异子 (m u tan t),如果测试用例能检测出这个变异子,就称它被“杀掉 (killed)” 了,如果植入的变异子不能被有效地杀掉,则说明测试用例不够,必须增加相应的测试用例。
传统的变异测试可直接用于方法测试中,但由于类和类簇等是传统程序所不具备的,所以必须为它们设计新的变异子。
9.基于使用的测试基于使用的测试是指在类或类簇的状态图或方法控制流图中加入有关使用的信息,即每一条路径的执行频率或其重要性,这些信息来自于系统的需求规范、设计者的经验、软件的应用环境以及类似程序的使用经验等。加入这些信息的目的是为了使测试者了解到程序的哪些部分使用的频率较高,以使之得到更为详尽的测试,另外应兼顾那些不是太常用但非常关键的路径,使其得到足够的测试。这种方法可以有效地指导测试用例的生成,并提高测试的效率。
第八章 面向对象的软件测试
8.3.2 类测试技术
10.测试程度可以根据已经测试了多少类实现和多少类说明来衡量测试的充分性。对于类的测试,通常需要将这两者都考虑到,
希望测试到操作和状态转换的各种组合情况。一个对象能维持自己的状态,而状态一般来说也会影响操作的含义。
但要穷举所有组合式不可能的,而且是没必要的 。因此,
就因该结合风险分析进行选择配对系列的组合,以致达到使用最重要的测试用例并抽取部分不太重要的测试用例。
11.类测试的范围
( 1)对认定的类的测试
OOD认定的类可以是 OOA中认定的对象,也可以是对象所需要的服务的抽象,对象所具有的属性的抽象。认定的类原则上应该尽量基础性,这样才便于维护和重用。
第八章 面向对象的软件测试
8.3.2 类测试技术
( 2)对构造的类层次结构的测试为能充分发挥面向对象的继承共享特性,OOD的类层次结构,通常基于 OOA中产生的分类结构的原则来组织,着重体现父类和子类间一般性和特殊性。两者概念上的差异。
在当前的问题空间,对类层次结构的主要要求是能在解空间构造实现全部功能的结构框架。为此,测试如下方面:
类层次结构是否含盖了所有定义的类;
是否能体现 OOA中所定义的实例关联;
是否能实现 OOA中所定义的消息关联;
子类是否具有父类没有的新特性;
子类间的共同特性是否完全在父类中得以体现。
第八章 面向对象的软件测试
8.3.2 类测试技术
( 3)对类库支持的测试对类库的支持虽然也属于类层次结构的组织问题,但其强调的重点是再次软件开发的重用。由于它并不直接影响当前软件的开发和功能实现,因此,将其单独提出来测试,
也可作为对高质量类层次结构的评估。参照 [9]中提出的准则,拟订测试点如下:
一组子类中关于某种含义相同或基本相同的操作,是否有相同的接口(包括名字和参数表);
类中方法( C++:类的成员函数)功能是否较单纯,相应的代码行是否较少( [5]中建议为不超过 30行);
类的层次结构是否是深度大,宽度小。
第八章 面向对象的软件测试
8.3.2 类测试技术
( 4)数据成员是否满足数据封装的要求数据封装是数据和数据有关的操作的集合。
检查数据成员是否满足数据封装的要求,
基本原则是数据成员是否被外界(数据成员所属的类或子类以外的调用)直接调用。
更直观的说,当改编数据成员的结构时,
是否影响了类的对外接口,是否会导致相应外界必须改动。值得注意,有时强制的类型转换会破坏数据的封装特性。例如:
第八章 面向对象的软件测试
8.3.2 类测试技术
class Hiden
{private:
int a=1;
char *p= "hiden";}
class Visible
{public:
int b=2;
char *s= "visible";}
..
..
Hiden pp;
Visible *qq=(Visible *)&pp;
在上面的程序段中,pp的数据成员可以通过 qq被随意访问。
第八章 面向对象的软件测试
8.3.2 类测试技术
( 5)类是否实现了要求的功能类所实现的功能,都是通过类的成员函数执行。在测试类的功能实现时,应该首先保证类成员函数的正确性。单独的看待类的成员函数,
与面向过程程序中的函数或过程没有本质的区别,几乎所有传统的单元测试中所使用的方法,都可在面向对象的单元测试中使用。具体的测试方法在面向对象的单元测试中介绍。类函数成员的正确行为只是类能够实现要求的功能的基础,类成员函数间的作用和类之间的服务调用是单元测试无法确定的。因此,需要进行面向对象的集成测试。
具体的测试方法在面向对象的集成测试中介绍。需要着重声明,测试类的功能,不能仅满足于代码能无错运行或被测试类能提供的功能无错,应该以所做的 OOD结果为依据,检测类提供的功能是否满足设计的要求,是否有缺陷。必要时(如通过 OOD结仍不清楚明确的地方)
还应该参照 OOA的结果,以之为最终标准。
第八章 面向对象的软件测试
8.3.2 类测试技术
①,如果函数(程序)对某一类输入中的一个数据正确执行,对同类中的其他输入也能正确执行。该假设的思想可参见 [6]中介绍的等价类划分。
②、如果函数(程序)对某一复杂度的输入正确执行,对更高复杂度的输入也能正确执行。例如需要选择字符串作为输入时,基于本假设,就无须计较于字符串的长度。除非字符串的长度是要求固定的,如 IP地址字符串。
在面向对象程序中,类成员函数通常都很小,功能单一,
函数的间调用频繁,容易出现一些不宜发现的错误。例如:
if (-1==write (fid,buffer,amount)) error_out();该语句没有全面检查 write()的返回值,无意中断然假设了只有数据被完全写入和没有写入两种情况。当测试也忽略了数据部分写入的情况,就给程序遗留了隐患。
第八章 面向对象的软件测试
8.3.2 类测试技术按程序的设计,使用函数 strrchr()查找最后的匹配字符,
但程序中写成了函数 strchr(),使程序功能实现时查找的是第一个匹配字符。程序中将 if
(strncmp(str1,str2,strlen(str1)))误写成了 if
(strncmp(str1,str2,strlen(str2)))。如果测试用例中使用的数据 str1和 str2长度一样,就无法检测出。
因此,在做测试分析和设计测试用例时,应该注意面向对象程序的这个特点,仔细的进行测试分析和设计测试用例,
尤其是针对以函数返回值作为条件判断选择,字符串操作等情况。
面向对象编程的特性使得对成员函数的测试,又不完全等同于传统的函数或过程测试。尤其是继承特性和多态特性,
使子类继承或过载的父类成员函数出现了传统测试中未遇见的问题。
第八章 面向对象的软件测试
8.3.3 类层次结构测试技术继承作为代码复用的一种机制,可能是面向对象软件开发产生巨大吸引力的一个重要因素。继承由扩展、覆盖和特例化三种基本机制实现的。其中,扩展是子类自动包含父类的特征;覆盖是子类中的方法与父类中的方法有相同的名字和消息参数以及相同的接口,但方法的实现不同;特例化是子类中特有的方法和实例变量。好的面向对象程序设计要求通过非常规范的方式使用继承 —— 即代码替代原则。在这种规则下,为一个类确定的测试用例集对该类的子类也是有效的。因此,
额外的测试用例通常应用于子类。通过仔细分析根据父类定义的子类的增量变化,有时候,子类中的某些部分可以不做执行测试。因为应用于父类中的测试用例所测试的代码被子类原封不动的继承,是同样的代码。
类的层次结构测试就是用来测试类的继承关系的技术,主要是用来测试层次关系的一系列类(包括父类和子类)。其测试的方法有用于测试子类的分层增量测试和用于测试父类的抽象类测试。
第八章 面向对象的软件测试
8.3.3 类层次结构测试技术分层、增量测试
C
D
Void op1 ( );
Void op2 ( );
Void op2 ( );
Void open ( );
Newvar type;
说明如下:
子类 D添加了一个新的实例变量( NewVar)和一个新的操作( newop( ))。
D重载了 C中定义的方法 op2(),因为该操作在 D中有新的规范或操作的实现。
分层增量测试( hierarchical incremental testing(HIT))指通过分析来确定子类的哪些测试用例需要添加,哪些继承的测试用例需要运行,以及哪些继承的测试用例不需要运行的测试方法。展示了 C类和它的派生类 D类,
以及它们之间的增量变化。 C类和它的派生类 D类间的增量变化能够用来帮助确定需要在 D中测试什么。
第八章 面向对象的软件测试
8.3.3 类层次结构测试技术由于 D类是 C类的子类,则所有用于 C类的基于规范的测试用例也都适用于 D类。那么,哪些继承的测试用例(用于子类的测试用例)适用于子类的测试,哪些又不必在子类中执行呢?要解决以上问题,可通过对子类的增量分析。
可能情况如下:
( 1) D的接口中添加一个或多个新的操作,并且有可能 D中的一个新方法实现一个新操作。新的操作引入了新的功能和新的代码,这些都需要测试。如果操作不是抽象的并且有具体的实现,那么为了合乎测试计划中的覆盖标准,需要添加基于规范和基于交互的测试用例。
( 2)通过两种方式改变由 C申明的操作的规范和实现:一,
在 D中改变那些在 D中申明的操作规范。二,在 D中覆盖那些在 C中实现了某个操作并且被 D继承了的方法。
第八章 面向对象的软件测试
8.3.3 类层次结构测试技术
( 3)在 D中添加一个或多个实例变量来实现更多的状态和属性。新添的变量最有可能与新的操作和重载方法中代码有关,而且对测试的处理也与他们有关。如果新的变量没有在任何地方使用,那么就不必做任何的变化。
( 4)在 D中改变类常量。类常量组成每个侧使用例的附加的后臵条件,
并且,“类常量句柄”在每个测试用例输出中是显示的。因此,如果类常量变化了,就需要重新运行所有继承的测试用例以验证常量句柄。
从基类派生出派生类时,不必为那些未经变化的操作添加基于规范的测试用例,测试用例能够不加修改的复用。如果测试的操作没有以任何方式加以修改,就不必运行这些测试用例中的任何一个。但是,如果一个操作的方法被间接的修改了,不但需要重新运行那些操作的任何一个测试用例,还需要运行附加的机遇实现的测试用例。
第八章 面向对象的软件测试
8.3.3 类层次结构测试技术
2.抽象类测试对类基于执行的测试时,需要建构一个类的实例。然而,一个继承体系的根类通常是抽象的,许多编程语言在语义上不允许建构抽象类的实例。这位抽象类的测试带来了很大的困难。在此,提出三种测试抽象类的方法:
( 1)需要测试的抽象类单独定义一个具体的子类。通过对具体子类创建的实例测试,来完成对抽象类的测试。这种方法的缺点是,如果不是用多层继承,抽象类的方法的实现就不能轻易的传递给抽象子类。但是大部分面向对象的编程语言都不支持多重继承,而且不提倡将多重继承用在这些方面。
( 2)将抽象类作为测试第一个具体子孙的一部分进行测试。这种方法不需要开发额外的用于测试的目的类,但需要考虑到为每一个祖先提供恰当的、
正确的测试用例和测试脚本方法,而增加了测试具体类的复杂性。
( 3)以对用于测试目的的抽象类的具体版本作直接实现,尝试找到一种为类编写源代码的方法,从而使得该类可以做为一个抽象或具体类而很容易编译。然而,不管是基于编辑遗产方案还是基于条件编译的方案都没有产生好的结果。应为合成代码都很复杂,而且难以阅读,很容易出错。
第八章 面向对象的软件测试
8.3.4 对象交互测试技术面向对象的软件是由若干对象组成的,通过这些对象的相续协作来解决某些问题。对象的交互和写作方式决定了程序能作什么,从而决定了这个程序执行的正确性。也许可信任的原始类的实例可能不包含任何错误,但是如果那个实例的服务部被其他程序组件正确的使用的话,那么这个程序也就包含了错误。因此,程序中对象的正确协作 ——
即交互 —— 对于程序的正确性是非常关键的。
对象的交互测试的重点是确保对象(这些对象的类已经被单独测试过)的消息传送能够正确进行。交互测试的执行可以使用嵌入到应用程序中的交互对象,或者在独立的测试工具(例如一个 Tester类)提供环境中,交互测试通过使得该环境中的对象相互交互而执行。
根据类的类型可以将对向交互测试分为汇集类测试和协作类测试。
第八章 面向对象的软件测试
8.3.4 对象交互测试技术汇集类测试汇集类指的是这样的一种类,这些类在他们的说明中使用对象,但是实际上从不和这些对象中的任何一个进行协作 —— 即他们从不请求这些对象的服务。相反,他们会表现出以下的一个或多个行为:
( 1)存放这些对象的引用(或指针),通常表现程序中的对象之间一对多的关系。
( 2)创建这些对象的实例。
( 3)删除这些对象的实例。
可以使用测试原始类的方法来测试汇集类,测试驱动程序要创建一些实例,
作为消息中的参数被传送给一个正在测试的集合。测试用例的中心目的主要是保证那些实例被正确加入集合和被正确的从集合中移出,以及测试用例说明的集合对其容量有所限制。因此,每个对象的准确的类(这些对象是用在汇集类的测试中)在确定汇集类的正确操作是不重要的,因为在一个集合实例和集合中的对象之间没有交互。假如在实际应用中可能要加入
40到 50条信息,那么生成的测试用例至少要增加 50条信息。如果无法估计出一个有代表性的上限,就必须使用集合中大量的对象进行测试。
第八章 面向对象的软件测试
8.3.4 对象交互测试技术如果汇集类不能为增加的新元素分配内存,就应该测试这个汇集类的行为,或者是可变数组这一结构,往往一次就为若干条信息分配空间。
在测试用例的执行期间,可以使用异常机制,帮助测试人员限制在测试用例执行期间可得到的内存容量的分配情况。如果已经使用了保护设计方法,那么,测试系列还应该包括否定系列。即当某些即和已拥有有限的制定容量,并且有实际的限制,则应该用超过指定的容量限制的测试用例进行测试。
3.协作类的测试凡不是汇集类的非原始类(原始累即一些简单的,独立的类,这些类可以用类测试方法进行测试)就是协作类。这种类在它们的一个或多个操作中使用其它的对象并将其作为他们的实现中不可缺少的一部分。
当接口中的一个操作的某个后臵条件引用了一个协作类的对象的实例状态,则说明那个对象的属性别使用或修改了。由此可见,协作类的测试的复杂性远远高于汇集类或者原始类测试的复杂性,鉴于协助类的测试需要根据具体的情况来定。
第八章 面向对象的软件测试
8.4 面向对象软件测试用例设计
OO测试用例设计包含 OO概念,在 OO度量中所讲的五个特性,局域性、封装性、信息隐藏、继承性和对象的抽象,肯定会对用例设计带来额外的麻烦和困难。 Berard提出了一些测试用例的设计方法,
主要原则包括,
1.每个测试用例应当给予特殊的标识,并且还应当与测试的类有明确的联系。
2.测试目的应当明确。
3.应当为每个测试用例开发一个测试步骤列表。
第八章 面向对象的软件测试
8.4 面向对象软件测试用例设计
8.4.1 基于故障的测试
8.4.2 基于脚本的测试
8.4.3 OO类的随机测试
8.4.4 类层次的分割测试
8.4.5 由行为模型(状态、活动、顺序和合作图)导出的测试
8.4.6 构建类测试用例第八章 面向对象的软件测试
8.4.1 基于故障的测试在 OO软件中,基于故障的测试具有较高的发现可能故障的能力。由于系统必须满足用户的需求,因此,基于故障的测试要从分析模型开始,
考察可能发生的故障。为了确定这些故障是否存在,可设计用例去执行设计或代码。
基于故障测试的关键取决于测试设计者如何理解“可能的错误”。而在实际中,要求设计者做到这点是不可能的。
基于故障测试也可以用于组装测试,组装测试可以发现消息联系中
“可能的故障”。,可能的故障”一般为意料之外的结果、错误地使用了操作 /消息、不正确引用等。为了确定由操作(功能)引起的可能故障必须检查操作的行为。
这种方法除用于操作测试外,还可用于属性测试,用以确定其对于不同类型的对象行为是否赋予了正确的属性值。因为一个对象的“属性”
是由其赋予属性的值定义的。
应当指出,组装测试是从客户对象(主动),而不是从服务器对象
(被动)上发现错误。正如传统的软件组装测试是把注意点集中在调用代码而不是被调用代码一样,即发现客户对象中“可能的故障”。
第八章 面向对象的软件测试
8.4.2 基于脚本的测试基于故障测试减少了两种主要类型的错误,一是不正确的规格说明,如做了用户不需要的功能,也可能缺少了用户需要的功能;二是子系统间的交互作用没有考虑,如一个子系统(事件或数据流等)的建立,导致其他子系统的失败。
基于脚本的测试主要关注用户需要做什么,而不是产品能做什么,即从用户任务(使用用例)中找出用户要做什么及去执行。
这种基于脚本的测试有助于在一个单元测试情况下检查多重系统。所以基于脚本测试用例测试比基于故障测试不仅更实际(接近用户),而且更复杂一点。
第八章 面向对象的软件测试
8.4.2 基于脚本的测试例如:考察一个文本编辑的基于脚本测试的用例设计。
使用用例:确定最终设计背景:打印最终设计,并能从屏幕图像上发现一些不易见到的且让人烦恼的错误。
其执行事件序列:打印整个文件;移动文件,修改某些页;当某页被修改,就打印某页;有时要打印许多页。
显然,测试者希望发现打印和编辑两个软件功能是否能够相互依赖,否则就会产生错误。
第八章 面向对象的软件测试
8.4.3 OO类的随机测试如果一个类有多个操作(功能),这些操作(功能)序列有多种排列。
而这种不变化的操作序列可随机产生,用这种可随机排列的序列来检查不同类实例的生存史,就叫随机测试。
例如一个银行信用卡的应用,其中有一个类:计算( account)。该
account的操作有,open,setup,deposit,withdraw,balance、
summarize,creditlimit和 close。
这些操作中的每一项都可用于计算,但 open,close必须在其他计算的任何一个操作前后执行,即使 open和 close有这种限制,这些操作仍有多种排列。所以一个不同变化的操作序列可由于应用不同而随机产生,如一个 Account实例的最小行为生存史可包括以下操作:
open+setup+deposit+[deposit|withdraw |balance|summarize|creditlimit]+withdraw+close 。
从此可见,尽管这个操作序列是最小测试序列,但在这个序列内仍可发生许多其他的行为。
第八章 面向对象的软件测试
8.4.4 类层次的分割测试这种测试可以减少用完全相同的方式检查类测试用例的数目。这很像传统软件测试中的等价类划分测试。分割测试又可分三种:
①基于状态的分割按类操作是否改变类的状态来分割(归类)。这里仍用 account类为例,改变状态的操作有 deposit,withdraw,不改变状态的操作有 balance、
summarize,creditlimit。如果测试按检查类操作是否改变类状态来设计,
则结果如下,
用例 1:执行操作改变状态
open+setup+deposit+deposit+withdraw+withdraw+close。
用例 2:执行操作不改变状态
open+setup+deposit+summarize+creditlimit+withdraw+close。
②基于属性的分割按类操作所用到的属性来分割(归类),如果仍以一个 account类为例,其属性 creditlimit能被分割为三种操作:用 creditlimit的操作,修改
creditlimit的操作,不用也不修改 creditlimit的操作。这样,测试序列就可按每种分割来设计。
③基于类型的分割按完成的功能分割。例如,在 account类的操作中,可以分割为:初始操作
open,setup;计算操作 deposit,withdraw;查询操作 balance,summarize、
creditlimit;终止操作 close。 第八章 面向对象的软件测试
8.4.5 由行为模型(状态、活动、顺序和合作图)导出的测试状态转换图( STD)可以用来帮助导出类的动态行为的测试序列,以及这些类与之合作的类的动态行为测试序列。
为了说明问题,仍用前面讨论过的 account类。开始由 empty acct状态转换为 setup acct状态。类实例的大多数行为发生在 working acct
状态中。而最后,取款和关闭分别使 account类转换到 non-working
acct和 dead acct状态。
这样,设计的测试用例应当是完成所有的状态转换。换句话说,操作序列应当能导致 account类所有允许的状态进行转换。
测试用例:
open+setupAcct+deposit(initial)+withdraw(final)+close 。
还可导出更多的测试用例,以保证该类所有行为被充分检查。
OO软件测试的主要目标与传统软件测试一样,即用最小量的投入来最大限度地发现软件存在的错误。但由于 OO软件具有的特殊性质,OO软件测试在内容、策略和方法上与传统软件测试不完全相同。
第八章 面向对象的软件测试
8.4.6 构建类测试用例要对类进行测试,就必须先确定和构建类的测试用例。类的描述方法有 OCL,自然语言,和状态图等方法,可以根据类说明的描述方法构件类的测试用例。因而,构建类的测试用例的方法有:根据类说明(用 OCL表示)确定测试用例和根据类的状态转换图来构建类的测试用例。
根据类的说明确定测试用例 用 OCL表示的类的说明中描述了类的每一个限定条件条件。在 OCL条件下分析每个逻辑关系,从而得到由这个条件的结构所对应的测试用例。
这种确定类的测试用例的方法叫做根据前臵条件和后臵条件构建测试用例。其总体思想是:为所有可能出现的组合情况确定测试用例需求。在这些可能出现的组合情况下,
可满足前臵条件,也能够到达后臵条件。根据这些需求,
创建测试用例;创建拥有特定输入值(常见值和特殊值)
的测试用例;确定它们的正确输出 —— 预期输出值。
第八章 面向对象的软件测试
8.4.6 构建类测试用例根据前臵条件和后臵条件创建测试用例的基本步骤如下:
( 1)确定在表 1中与前臵条件形成相匹配的各个项目所指定的一系列前臵条件的影响。
( 2)确定在表 2中与后臵条件形成相匹配的各个项目所指定的一系列前臵条件的影响。
( 3)根据影响到列表中各个项目的所有可能的组合情况从而构造测试用例需求。一种简单的方法就是:用第一个列表中的每一个输入约束来代替第二个列表中每一个前臵条件。
( 4)排除表中生成的所有无意义的条件。
第八章 面向对象的软件测试
8.4.6 构建类测试用例表 8-1 前置条件对测试系列的影响前臵条件 影 响
True (true,post)
A (A,post)(not A,exception) *
Not A (not A,post)(A,exception) *
A and B
(A and B,post)
(not A and B,exception) *
(A and not B,exception) *
(not A and not B,exception) *
A or B
(A,post)
(B,post)
(A and B,post)
(not A and not B,post)
A xor B
(not A and B,post)
(A and not B,post)
(A and B,exception) *
(not A and not B,exception) *
A implies B
(not A,post)
(B,post)
(not A and B,post)
(A and not B,exception) *
if A then B
else C endif
(A and B,post)
(not A and C,post)
(A and not B,exception) *
(not A and not C,exception) *第八章 面向对象的软件测试
8.4.6 构建类测试用例表 8-2 后置条件对测试系列的影响后臵条件 影 响
A (pre ; A)
A and B (pre ; A and B)
A or B
(pre ; A)
(pre ; B)
(pre ; A or B)
A xor B (pre ; not A or B)(pre ; A or not B)
A implies B (pre ; not A or B)
if A then B
else C endif
(pre and * ; B)
(pre and not * ; C)
第八章 面向对象的软件测试和根据前臵条件和后臵条件创建类的测试用例相比,根据状态转换图创建类的测试用例有非常大的优势。
8.5 面向对象测试基本步骤
8.5.1 单元测试
8.5.2 组装测试
8.5.3 确认测试第八章 面向对象的软件测试
8.5.1 单元测试面向对象测试计划完成以后,就可以进行单元测试了。与传统的单元
(模块)不同,OO中的单元是类。每个类都封装了属性(数据)和管理这些数据的操作。一 个类可以包含许多不同的操作,一个特殊的操作可以出现在许多不同的类中。
传统的单元测试只能测试一个操作(功能)。而在 OO单元测试中,一个操作功能只能作为一个类的一部分,类中有多个操作(功能),就要进行多个操作的测试。
另外,父类中定义的某个操作被许多子类继承。但在实际应用中,不同子类中某个操作在使用时又有细微的不同,所以还必须对每个子类中某个操作进行测试。
类的测试可以使用多种方法,如基于故障的测试、随机测试和分割测试等。每一种方法都要检查封装在类中的操作,即设计的测试序列
(用例),要保证相关的操作被检查。因为类的属性值表示类的状态,
由此来确定被检查的错误是否存在。
第八章 面向对象的软件测试
8.5.2 组装测试传统软件的层次模块间存在着控制关系,而 OO软件没有层次控制结构。所以传统的自顶向下和自底向上的组装策略在 OO软件组装测试中就没有意义了。
另外,一个类每次组装一个操作(传统软件的增量法)在 OO软件组装中是不够的,因为组成类的各个成分之间存在着直接或间接的交互作用。 OO软件的组装测试有两种不同的策略:
1.基于线程测试 (thread-based-testing)
基于线程的测试就是把合作对应一个输入或事件的类集合组装起来,也就是用响应系统的一个输入或一个事件的请求来组装类的集合。对每个线程都要分别进行组装和测试。
2.基于使用测试 (use-based-testing)
基于使用的测试就是按分层来组装系统,可以先进行独立类的测试。在独立类测试之后,下一个类的层次叫从属类。从属类用独立类进行测试。这种从属类层的顺序测试直到整个系统被构造完成。传统软件使用驱动程序和连接程序作为臵换操作,而 OO软件一般不用。
OO系统组装时还必须进行类间合作(强调上下级关系)的测试。类的合作测试与单个类测试相似,可用随机应用和分割测试来完成。还可以用基于脚本测试和行为模型导出的测试进行。
第八章 面向对象的软件测试
8.5.3 确认测试确认测试是在系统层进行测试,因此类间的联系细节出现了。与传统软件一样,OO
软件确认测试也主要集中在用户可见活动和用户可识别的系统输出上,所以 OO软件也使用传统软件的黑盒子测试方法。确认测试大多使用基于脚本( scenarios)的测试,因而使用用例成为确认测试的主要驱动器。
第八章 面向对象的软件测试
8.6 面向对象测试工具 JUnit
通过前面介绍,我们对面向对象测试有了一定了解,如果想提高面向对象测试的效率,那么应该选择一个合适与面向对象的测试工具,下面主要介绍用于测试由 java
语言编写的面向对象程序的测试工具 JUnit。
第八章 面向对象的软件测试
8.6 面向对象测试工具 JUnit
8.6.1 Junit简介
8.6.2 JUnit的安装和配臵
8.6.3 JUnit中常用的接口和类
8.6.4 用 Junit进行类测试实例第八章 面向对象的软件测试
8.6.1 Junit简介
JUnit是一个开源的 java单元测试框架。在 1997年,由 Erich Gamma
和 Kent Beck 开发完成。 Erich Gamma是 GOF 之一; Kent Beck 则在
XP 中有重要的贡献。点击 http://www.junit.org可以下载到最新版本的 Junit。
这样,在系统中就可以使用 JUnit编写单元测试代码了。
“麻雀虽小,五脏俱全。” JUnit设计的非常小巧,但是功能却非常强大。
下面是 JUnit一些特性的总结;
提供的 API可以让你写出测试结果明确的可重用单元测试用例;
提供了三种方式来显示你的测试结果,而且还可以扩展;
提供了单元测试用例成批运行的功能;
超轻量级而且使用简单,没有商业性的欺骗和无用的向导;
整个框架设计良好,易扩展。
对不同性质的被测对象,如 Class,Jsp,Servlet,Ejb等,Junit有不同的使用技巧。下面以类测试为例加以介绍。
第八章 面向对象的软件测试
8.6.2 JUnit的安装和配置
1.将下载的 Junit压缩包解压到一个物理目录中(例如 E:
\ Junit3.8.1)。
2.记录 Junit.jar文件所在目录名(例如 E:\
Junit3.8.1\Junit.jar)。
3.进入操作系统(以 Windows2000操作系统为例),按照次序点击“开始 → 设臵 → 控制面板”。在控制面板选项中选择“系统”,点击“环境变量”,在“系统变量”的“变量”列表框中选择,CLASS-PATH” 关键字(不区分大小写),如果该关键字不存在则添加。 双击,CLASS-PATH”
关键字添加字符串,E:\ Junit3.8.1\Junti.jar”( 注意,
如果已有别的字符串请在该字符串的字符结尾加上分号
“;” ),然后确定,Junit就可以在集成环境中应用了。
第八章 面向对象的软件测试
8.6.3 JUnit中常用的接口和类
1,Test接口(运行测试和收集测试结果 )
Test接口使用了 Composite设计模式,是单独测试用例 ( TestCase),聚合测试模式( TestSuite)及测试扩展( TestDecorator)的共同接口。它的
public int countTestCases()方法,它来统计这次测试有多少个 TestCase,
另外一个方法就是 public void run( TestResult ),TestResult是实例接受测试结果,run方法执行本次测试。
2,TestCase抽象类(定义测试中固定方法)
TestCase是 Test接口的抽象实现,(不能被实例化,只能被继承)其构造函数 TestCase(string name)根据输入的测试名称 name创建一个测试实例。由于每一个 TestCase在创建时都要有一个名称,若某测试失败了,便可识别出是哪个测试失败。
TestCase类中包含的 setUp(),tearDown()方法。 setUp()方法集中初始化测试所需的所有变量和实例,并且在依次调用测试类中的每个测试方法之前再次执行 setUp()方法。 tearDown()方法则是在每个测试方法之后,释放测试程序方法中引用的变量和实例。
开发人员编写测试用例时,只需继承 TestCase,来完成 run方法即可,然后
JUnit获得测试用例,执行它的 run方法,把测试结果记录在 TestResult之中。
第八章 面向对象的软件测试
8.6.3 JUnit中常用的接口和类
3,Assert静态类(系列断言方法的集合)
Assert包含了一组静态的测试方法,用于期望值和实际值比对是否正确,即测试失败,Assert类就会抛出一个 AssertionFailedError异常,JUnit测试框架将这种错误归入 Failes并加以记录,同时标志为未通过测试。如果该类方法中指定一个 String类型的传参则该参数将被做为 AssertionFailedError异常的标识信息,告诉测试人员改异常的详细信息。
JUnit 提供了 6大类 31组断言方法,包括基础断言、数字断言、字符断言、布尔断言、对象断言。
其中 assertEquals( Object expcted,Object actual)内部逻辑判断使用
equals()方法,这表明断言两个实例的内部哈希值是否相等时,最好使用该方法对相应类实例的值进行比较。而 assertSame( Object expected,Object
actual)内部逻辑判断使用了 Java运算符,==”,这表明该断言判断两个实例是否来自于同一个引用( Reference),最好使用该方法对不同类的实例的值进行比对。 asserEquals(String message,String expected,String
actual)该方法对两个字符串进行逻辑比对,如果不匹配则显示着两个字符串有差异的地方。 ComparisonFailure类提供两个字符串的比对,不匹配则给出详细的差异字符。
第八章 面向对象的软件测试
8.6.3 JUnit中常用的接口和类
4,TestSuite测试包类(多个测试的组合)
TestSuite类负责组装多个 Test Cases。待测得类中可能包括了对被测类的多个测试,而 TestSuit
负责收集这些测试,使我们可以在一个测试中,
完成全部的对被测类的多个测试。
TestSuite类实现了 Test接口,且可以包含其它的
TestSuites。它可以处理加入 Test时的所有抛出的异常。
TestSuite处理测试用例有 6个规约(否则会被拒绝执行测试)
第八章 面向对象的软件测试
8.6.3 JUnit中常用的接口和类
测试用例必须是公有类( Public);
测试用例必须继承与 TestCase类;
测试用例的测试方法必须是公有的
( Public );
测试用例的测试方法必须被声明为 Void;
测试用例中测试方法的前臵名词必须是
test;
测试用例中测试方法误任何传递参数。
第八章 面向对象的软件测试
8.6.3 JUnit中常用的接口和类
5,TestResult结果类和其它类与接口
TestResult结果类集合了任意测试累加结果,通过
TestResult实例传递个每个测试的 Run()方法。
TestResult在执行 TestCase时如果失败会异常抛出
TestListener接口是个事件监听规约,可供 TestRunner类使用。它通知 listener的对象相关事件,方法包括测试开始 startTest(Test test),测试结束 endTest(Test test),
错误,增加异常 addError(Test test,Throwable t)和增加失败 addFailure(Test test,AssertionFailedError
t),TestFailure失败类是个“失败”状况的收集类,解释每次测试执行过程中出现的异常情况。其 toString()方法返回“失败”状况的简要描述。
第八章 面向对象的软件测试
8.6.4 用 Junit进行类测试实例我们就以一个简单的例子入手。这是一个只会做两数加减的超级简单的计算器的 java类程序代码:
public class SampleCalculator
{
public int add(int augend,int addend)
{
return augend + addend;
}
public int subtration(int minuend,int subtrahend)
{
return minuend – subtrahend;
}
}
将上面的代码编译通过。下面就是为上面程序写的一个单元测试用例(请注意这个程序里面类名和方法名的特征):
第八章 面向对象的软件测试
8.6.4 用 Junit进行类测试实例
import junit.framework.TestCase;
public class TestSample extends TestCase
{
public void testAdd()
{
SampleCalculator calculator = new SampleCalculator();
int result = calculator.add(50,20);
assertEquals(70,result);
}
public void testSubtration();
{
SampleCalculator calculator = new SampleCalculator();
int result = calculator.subtration(50,20);
assertEquals(30,result);
}
}
第八章 面向对象的软件测试
8.6.4 用 Junit进行类测试实例然后在 DOS命令行里面输入 javac TestSample.java 将测试类编译通过。再输入 java junit.swingui.TestRunner
TestSample 运行测试类,将会看到测试结果,绿色说明单元测试通过,没有错误产生;如果是红色的,则就是说测试失败了。这样一个简单的单元测试就完成了。
按照框架规定:编写的所有测试类,必须继承自
junit.framework.TestCase类;里面的测试方法,命名应该以 Test开头,必须是 public void 而且不能有参数;而且为了测试查错方便,尽量一个 TestXXX方法对一个功能单一的方法进行测试;使用 assertEquals等
junit.framework.TestCase中的断言方法来判断测试结果正确与否。 经过简单的类测试学习,可以编写标准的类测试用例了。
第八章 面向对象的软件测试习题
1,名词解释,面向对象、消息、封装性、继承性、多态性、类测试。
2,简述面向对象的基本概念及特点。
3,面向对象测试与传统测试有哪些区别与联系?
4,简述面向对象测试步骤。
5,什么是类测试,主要方法是什么?
第八章 面向对象的软件测试