面向对象软件的测试
前言
?什么是软件测试? 1983年 IEEE定义为:
使用人工或自动手段来运行或测定某个系
统的过程,其目的在于检验它是否满足规
定的需求或是弄清预期结果与实际结果之
间的差别。
前言
?现代的软件开发工程是将整个软件开发过
程明确的划分为几个阶段,将复杂问题具
体按阶段加以解决。这样,在软件的整个
开发过程中,可以对每一阶段提出若干明
确的监控点,作为各阶段目标实现的检验
标准,从而提高开发过程的可见度和保证
开发过程的正确性。
前言
?软件的质量不仅是体现在程序的正确性上,
它和编码以前所做的需求分析,软件设计
密切相关。
?软件测试的概念和实施范围应该包括在整
个开发各阶段的复查、评估和检测。由此,
广义的软件测试实际是由确认、验证、测
试三个方面组成
前言
?确认:是评估将要开发的软件产品是否是
正确无误、可行和有价值的。比如,将要
开发的软件是否会满足用户提出的要求,
是否能在将来的实际使用环境中正确稳定
的运行,是否存在隐患等。这里包含了对
用户需求满足程度的评价。确认意味着确
保一个待开发软件是正确无误的,是对软
件开发构想的检测
前言
?验证:是检测软件开发的每个阶段、每个
步骤的结果是否正确无误,是否与软件开
发各阶段的要求或期望的结果相一致。验
证意味着确保软件是会正确无误的实现软
件的需求,开发过程是沿着正确的方向在
进行。
一 前言
?测试:与狭隘的测试概念统一。通常是经
过单元测试、集成测试、系统测试三个环
节。
?确认 主要体现在计划阶段、需求分析阶段、
也会出现在测试阶段; 验证 主要体现在设
计阶段和编码阶段; 测试 主要体现在编码
阶段和测试阶段。
一 前言
?面向对象技术开发出的程序无需进行测试?
?面向对象程序的结构不再是传统的功能模
块结构,作为一个整体,原有集成测试所
要求的逐步将开发的模块搭建在一起进行
测试的方法已成为不可能。
二 面向对象测试模型
?面向对象的开发模型突破了传统的瀑布模
型,将开发分为面向对象分析( OOA),
面向对象设计( OOD),和面向对象编程
( OOP)三个阶段。分析阶段产生整个问
题空间的抽象描述,在此基础上,进一步
归纳出适用于面向对象编程语言的类和类
结构,最后形成代码。
二 面向对象测试模型
?
OOA Test:面向对象分析的测试
OOD Test:面向对象设计的测试
OOP Test:面向对象编程的测试
OO Unit Test:面向对象单元测试
OO Integrate Test:面向对象集成测试
OO System Test:面向对象系统测试
三 面向对象分析的测试
?面向对象分析( OOA)是 "把 E-R图和语义
网络模型,即信息造型中的概念,与面向
对象程序设计语言中的重要概念结合在一
起而形成的分析方法 ",最后通常是得到问
题空间的图表的形式描述。
三 面向对象分析的测试
? OOA直接映射问题空间,全面的将问题空间中实
现功能的现实抽象化。将问题空间中的实例抽象
为对象(不同于 C++中的对象概念),用对象的
结构反映问题空间的复杂实例和复杂关系,用属
性和服务表示实例的特性和行为。对一个系统而
言,与传统分析方法产生的结果相反,行为是相
对稳定的,结构是相对不稳定的,这更充分反映
了现实的特性。 OOA的结果是为后面阶段类的选
定和实现,类层次结构的组织和实现提供平台
三 面向对象分析的测试
?OOA对问题空间分析抽象的不完整,最终
会影响软件的功能实现,导致软件开发后
期大量可避免的修补工作;而一些冗余的
对象或结构会影响类的选定、程序的整体
结构或增加程序员不必要的工作量。
三 面向对象分析的测试
?对 OOA阶段的测试划分为以下五个方面:
☆ 对认定的对象的测试
☆ 对认定的结构的测试
☆ 对认定的主题的测试
☆ 对定义的属性和实例关联的测试
☆ 对定义的服务和消息关联的测试
三 面向对象分析的测试
? 1 对认定的对象的测试:
OOA中认定的对象是对问题空间中的结构,其他系统,
设备,被记忆的事件,系统涉及的人员等实际实例的抽象。
对它的测试可以从如下方面考虑:
1.1 认定的对象是否全面,是否问题空间中所有涉及到的实
例都反映在认定的抽象对象中。
1.2 认定的对象是否具有多个属性。只有一个属性的对象通
常应看成其他对象的属性,而不是抽象为独立的对象。
1.3 对认定为同一对象的实例是否有共同的,区别于其他实
例的共同属性。
1.4 对认定为同一对象的实例是否提供或需要相同的服务,
如果服务随着不同的实例而变化,认定的对象就需要分解或利用 继承性来分类表示。
1.5 如果系统没有必要始终保持对象代表的实例的信息,提
供或者得到关于它的服务,认定的对象也无必要。
1.6 认定的对象的名称应该尽量准确,适用。
三 面向对象分析的测试
?2 对认定的结构的测试
认定的结构指的是多种对象的组织方式,
用来反映问题空间中的复杂实例和复杂关
系。认定的结构分为两种:分类结构和组
装结构。分类结构体现了问题空间中实例
的一般与特殊的关系,组装结构体现了问
题空间中实例整体与局部的关系。
三 面向对象分析的测试
? 2.1 对认定的分类结构的测试可从如下方面着手:
2.1.1 对于结构中的一种对象,尤其是处于高层
的对象,是否在问题空间中含有不同于下一层对象的特殊
可能性,即是否能派生出下一层对象。
2.1.2 对于结构中的一种对象,尤其是处于同一
低层的对象,是否能抽象出在现实中有意义的更一般的上
层对象。
2.1.3 对所有认定的对象,是否能在问题空间内
向上层抽象出在现实中有意义的对象
2.1.4 高层的对象的特性是否完全体现下层的共
性
2.1.5 低层的对象是否有高层特性基础上的特殊
性
三 面向对象分析的测试
? 2.2 对认定的组装结构的测试从如下方面入手:
2.2.1 整体(对象)和部件(对象)的
组装关系是否符合现实的关系。
2.2.2 整体(对象)的部件(对象)是
否在考虑的问题空间中有实际应用。
2.2.3 整体(对象)中是否遗漏了反映
在问题空间中有用的部件(对象)。
2.2.4 部件(对象)是否能够在问题空
间中组装新的有现实意义的整体(对象)。
三 面向对象分析的测试
? 3 对认定的主题的测试
主题是在对象和结构的基础上更高一层的抽象,是为
了提供 OOA分析结果的可见性,如同文章对各部分内容的
概要。对主题层的测试应该考虑以下方面:
3.1 贯彻 George Miller 的 "7+2"原则,如果主题个数超过 7
个,就要求对有较密切属性和服务的主题进行归并。
3.2 主题所反映的一组对象和结构是否具有相同和相近的属
性和服务。
3.3 认定的主题是否是对象和结构更高层的抽象,是否便于
理解 OOA结果的概貌(尤其是对非技术人员的 OOA 结果读者)。
3.4 主题间的消息联系(抽象)是否代表了主题所反映的对
象和结构之间的所有关联。
三 面向对象分析的测试
? 4 对定义的属性和实例关联的测试
属性是用来描述对象或结构所反映的实例的特性。而
实例关联是反映实例集合间的映射关系。对属性和实例关
联的测试从如下方面考虑:
4.1 定义的属性是否对相应的对象和分类结构的每个现实实
例都适用。
4.2 定义的属性在现实世界是否与这种实例关系密切。
4.3 定义的属性在问题空间是否与这种实例关系密切。
4.4 定义的属性是否能够不依赖于其他属性被独立理解。
4.5 定义的属性在分类结构中的位置是否恰当,低层对象的
共有属性是否在上层对象属性体现。
4.6 在问题空间中每个对象的属性是否定义完整。
4.7 定义的实例关联是否符合现实。
4.8 在问题空间中实例关联是否定义完整,特别需要注意 1-
多和多 -多的实例关联。
三 面向对象分析的测试
? 5 对定义的服务和消息关联的测试
定义的服务,就是定义的每一种对象和结构在问题空
间所要求的行为。由于问题空中实例间必要的通信,在
OOA 中相应需要定义消息关联。对定义的服务和消息关
联的测试从如下方面进行:
5.1 对象和结构在问题空间的不同状态是否定义了相应的服
务。
5.2 对象或结构所需要的服务是否都定义了相应的消息关联。
5.3 定义的消息关联所指引的服务提供是否正确。
5.4 沿着消息关联执行的线程是否合理,是否符合现实过程。
5.5 定义的服务是否重复,是否定义了能够得到的服务。
四 面向对象设计的测试
?面向对象设计( OOD)采用 "造型的观点 ",
以 OOA为基础归纳出类,并建立类结构或
进一步构造成类库,实现分析结果对问题
空间的抽象。 OOD 归纳的类,可以是对象
简单的延续,可以是不同对象的相同或相
似的服务。由此可见,OOD不是在 OOA上
的另一思维方式的大动干戈,而是 OOA的
进一步细化和更高层的抽象。
四 面向对象设计的测试
?, OOD与 OOA 的界限通常是难以严格区分的。
OOD确定类和类结构不仅是满足当前需求分析的
要求,更重要的是通过重新组合或加以适当的补
充,能方便实现功能的重用和扩增,以不断适应
用户的要求。因此,对 OOD的测试,针对功能的
实现和重用以及对 OOA结果的拓展,从如下三方
面考虑:
☆ 对认定的类的测试
☆ 对构造的类层次结构的测试
☆ 对类库的支持的测试
四 面向对象设计的测试
? 1 对认定的类的测试
OOD认定的类可以是 OOA中认定的对象,也
可以是对象所需要的服务的抽象,对象所具有的
属性的抽象。认定的类原则上应该尽量基础性,
这样才便于维护和重用。测试认定的类:
1.1 是否含盖了 OOA中所有认定的对象。
1.2 是否能体现 OOA中定义的属性。
1.3 是否能实现 OOA中定义的服务。
1.4 是否对应着一个含义明确的数据抽象。
1.5 是否尽可能少的依赖其他类。
1.6 类中的方法( C++:类的成员函数)是
否单用途。
四 面向对象设计的测试
? 2 对构造的类层次结构的测试
为能充分发挥面向对象的继承共享特性,OOD的类
层次结构,通常基于 OOA中产生的分类结构的原则来组织,
着重体现父类和子类间一般性和特殊性。两者概念上的差
异。在当前的问题空间,对类层次结构的主要要求是能在
解空间构造实现全部功能的结构框架。为此,测试如下方
面:
2.1 类层次结构是否含盖了所有定义的类。
2.2 是否能体现 OOA中所定义的实例关联。
2.3 是否能实现 OOA中所定义的消息关联。
2.4 子类是否具有父类没有的新特性。
2.5 子类间的共同特性是否完全在父类中得以体现。
四 面向对象设计的测试
? 3 对类库支持的测试
对类库的支持虽然也属于类层次结构的组织
问题,但其强调的重点是再次软件开发的重用。
由于它并不直接影响当前软件的开发和功能实现,
因此,将其单独提出来测试,也可作为对高质量
类层次结构的评估。测试点如下:
3.1 一组子类中关于某种含义相同或基本相同的
操作,是否有相同的接口(包括名字和参数表)。
3.2 类中方法( C++:类的成员函数)功能是否
较单纯,相应的代码行是否较少。
3.3 类的层次结构是否是深度大,宽度小。
五 面向对象编程的测试
?典型的面向对象程序具有继承、封装和多
态的新特性,这使得传统的测试策略必须
有所改变。封装是对数据的隐藏,外界只
能通过被提供的操作来访问或修改数据,
这样降低了数据被任意修改和读写的可能
性,降低了传统程序中对数据非法操作的
测试。继承是面向对象程序的重要特点,
继承使得代码的重用率提高,同时也使错
误传播的概率提高。
五 面向对象编程的测试
?继承使得传统测试遇见了这样一个难题:
对继承的代码究竟应该怎样测试?多态使
得面向对象程序对外呈现出强大的处理能
力,但同时却使得程序内 "同一 "函数的行为
复杂化,测试时不得不考虑不同类型具体
执行的代码和产生的行为。
五 面向对象编程的测试
? 面向对象程序是把功能的实现分布在类中。能正
确实现功能的类,通过消息传递来协同实现设计
要求的功能。正是这种面向对象程序风格,将出
现的错误能精确的确定在某一具体的类。因此,
在面向对象编程( OOP)阶段,忽略类功能实现
的细则,将测试的目光集中在类功能的实现和相
应的面向对象程序风格,主要体现为以下两个方
面(假设编程使用 C++语言):
☆ 数据成员是否满足数据封装的要求
☆ 类是否实现了要求的功能
五 面向对象编程的测试
?1 数据成员是否满足数据封装的要求
数据封装是数据和数据有关的操作的
集合。检查数据成员是否满足数据封装的
要求,基本原则是数据成员是否被外界
(数据成员所属的类或子类以外的调用)
直接调用。更直观的说,当改编数据成员
的结构时,是否影响了类的对外接口,是
否会导致相应外界必须改动。值得注意,
有时强制的类型转换会破坏数据的封装特
性。
四 面向对象设计的测试
? 例如:
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被随
意访问。
五 面向对象编程的测试
?2 类是否实现了要求的功能
? 类所实现的功能,都是通过类的成员函数执行。
在测试类的功能实现时,应该首先保证类成员
函数的正确性。单独的看待类的成员函数,与
面向过程程序中的函数或过程没有本质的区别,
几乎所有传统的单元测试中所使用的方法,都
可在面向对象的单元测试中使用。
五 面向对象编程的测试
? 类函数成员的正确行为只是类能够实现要求
的功能的基础,类成员函数间的作用和类之间
的服务调用是单元测试无法确定的。因此,需
要进行面向对象的集成测试。
? 测试类的功能,不能仅满足于代码能无错运行
或被测试类能提供的功能无错,应该以所做的
OOD结果为依据,检测类提供的功能是否满足
设计的要求,是否有缺陷。必要时(如通过
OOD结仍不清楚明确的地方)还应该参照
OOA的结果,以之为最终标准。
六 面向对象的单元测试
?传统的单元测试是针对程序的函数、过程
或完成某一定功能的程序块。沿用单元测
试的概念,实际测试类成员函数。一些传
统的测试方法在面向对象的单元测试中都
可以使用。如等价类划分法,因果图法,
边值分析法,逻辑覆盖法,路径分析法,
等等,单元测试一般建议由程序员完成。
六 面向对象的单元测试
? 用于单元级测试进行的测试分析(提出相应的测
试要求)和测试用例(选择适当的输入,达到测
试要求),规模和难度等均远小于后面将介绍的
对整个系统的测试分析和测试用例,而且强调对
语句应该有 100%的执行代码覆盖率。在设计测
试用例选择输入数据时,可以基于以下两个假设:
1,如果函数(程序)对某一类输入中的一个
数据正确执行,对同类中的其他输入也能正确执
行。
2,如果函数(程序)对某一复杂度的输入正
确执行,对更高复杂度的输入也能正确执行。
六 面向对象的单元测试
?例如需要选择字符串作为输入时,基于本
假设,就无须计较于字符串的长度。除非
字符串的长度是要求固定的,如 IP地址字
符串。在面向对象程序中,类成员函数通
常都很小,功能单一,函数的间调用频繁,
容易出现一些不宜发现的错误。
六 面向对象的单元测试
? 例如:
? ·if (-1==write (fid,buffer,amount)) error_out();
该语句没有全面检查 write()的返回值,无意中断然假设
了只有数据被完全写入和没有写入两种情况。当测试也忽
略了数据部分写入的情况,就给程序遗留了隐患。
·按程序的设计,使用函数 strrchr()查找最后的匹配字符,
但误程序中写成了函数 strchr(),使程序功能实现时查找
的是第一个匹配字符。
·程序中将 if (strncmp(str1,str2,strlen(str1)))误写成
了 if (strncmp(str1,str2,strlen(str2)))。如果测试用
例中使用的数据 str1和 str2长度一样,就无法检测出。
六 面向对象的单元测试
?面向对象编程的特性使得对成员函数的测
试,又不完全等同于传统的函数或过程测
试。尤其是继承特性和多态特性,使子类
继承或过载的父类成员函数出现了传统测
试中未遇见的问题。 Brian Marick 给出了
二方面的考虑:
六 面向对象的单元测试
? 1,继承的成员函数是否都不需要测试?
对父类中已经测试过的成员函数,两种情况
需要在子类中重新测试,a)继承的成员函数在子
类中做了改动; b)成员函数调用了改动过的成员
函数的部分。例如:
假设父类 Bass有两个成员函数,Inherited()
和 Redefined(),子类 Derived只对 Redefined()
做了改动。 Derived::Redefined()显然
需要重新测试。对于 Derived::Inherited(),如
果它有调用 Redefined()的语句 (如:
x=x/Redefined()),就需要重新测试,反之,无
此必要。
六 面向对象的单元测试
?2,对父类的测试是否能照搬到子类?
援用上面的假设,Base::Redefined()
和 Derived::Redefined()已经是不同的成
员函数,它们有不同的服务说明和执行。
对此,照理应该对 Derived::Redefined()
重新测试分析,设计测试用例。但由于面
向对象的继承使得两个函数有相似,故只
需在 Base::Redefined()的测试要求和测
试用例上添加对 Derived::Redfined()新
的测试要求和增补相应的测试用例。
六 面向对象的单元测试
? 例如:
Base::Redefined()含有如下语句
If (value<0) message ("less");
else if (value==0) message ("equal");
else message ("more");
Derived::Redfined()中定义为
If (value<0) message ("less");
else if (value==0) message ("It is equal");
else
{message ("more");
if (value==88)message("luck");}
在原有的测试上,对 Derived::Redfined()的测试只
需做如下改动:将 value==0的测试结果期望改动;增加
value==88的测试。
七 面向对象的集成测试
? 传统的集成测试,是由底向上通过集成完成的功能模块进
行测试,一般可以在部分程序编译完成的情况下进行。
? 对于面向对象程序,相互调用的功能是散布在程序的不同
类中,类通过消息相互作用申请和提供服务。类的行为与
它的状态密切相关,状态不仅仅是体现在类数据成员的值,
也许还包括其他类中的状态信息。由此可见,类相互依赖
极其紧密,根本无法在编译不完全的程序上对类进行测试。
面向对象的集成测试通常需要在整个程序编译完成后进行。
? 面向对象程序具有动态特性,程序的控制流往往无法确定,
因此也只能对整个编译后的程序做基于黑盒子的集成测试。
七 面向对象的集成测试
?面向对象的集成测试能够检测出相对独立
的单元测试无法检测出的那些类相互作用
时才会产生的错误。基于单元测试对成员
函数行为正确性的保证,集成测试只关注
于系统的结构和内部的相互作用。面向对
象的集成测试可以分成两步进行:先进行
静态测试,再进行动态测试。
七 面向对象的集成测试
?静态测试主要针对程序的结构进行,检测
程序结构是否符合设计要求。现在流行的
一些测试软件都能提供一种称为, 可逆性
工程, 的功能,即通过原程序得到类关系
图和函数功能调用关系图。
七 面向对象的集成测试
? 动态测试设计测试用例时,通常需要上述的功能
调用结构图、类关系图或者实体关系图为参考,
确定不需要被重复测试的部分,从而优化测试用
例,减少测试工作量,使得进行的测试能够达到
一定覆盖标准。测试所要达到的覆盖标准可以是:
达到类所有的服务要求或服务提供的一定覆盖率;
依据类间传递的消息,达到对所有执行线程的一
定覆盖率;达到类的所有状态的一定覆盖率等。
同时也可以考虑使用现有的一些测试工具 来得到
程序代码执行的覆盖率。
七 面向对象的集成测试
? 具体设计测试用例,参考下列步骤:
1,先选定检测的类,参考 OOD分析结果,
仔细出类的状态和相应的行为,类或成员函数间
传递的消息,输入或输出的界定等。
2,确定覆盖标准。
3,利用结构关系图确定待测类的所有关联。
4,根据程序中类的对象构造测试用例,确认
使用什么输入激发类的状态、使用类的服务和期
望产生什么行为等。
七 面向对象的集成测试
?注,设计测试用例时,不但要设计确认类
功能满足的输入,还应该有意识的设计一
些被禁止的例子,确认类是否有不合法的
行为产生,如发送与类状态不相适应的消
息,要求不相适应的服务等。根据具体情
况,动态的集成测试,有时也可以通过系
统测试完成。
八 面向对象的系统测试
? 通过单元测试和集成测试,仅能保证软件开发的
功能得以实现。但不能确认在实际运行时,它是
否满足用户的需要,是否大量存在实际使用条件
下会被诱发产生错误的隐患。为此,对完成开发
的软件必须经过规范的系统测试。
? 开发完成的软件仅仅是实际投入使用系统的一个
组成部分,需要测试它与系统其他部分配套运行
的表现,以保证在系统各部分协调工作的环境下
也能正常工作。
八 面向对象的系统测试
?系统测试应该尽量搭建与用户实际使用环
境相同的测试平台,应该保证被测系统的
完整性,对临时没有的系统设备部件,也
应有相应的模拟手段。系统测试时,应该
参考 OOA分析的结果,对应描述的对象、
属性和各种服务,检测软件是否能够完全 "
再现 "问题空间。系统测试不仅是检测软件
的整体行为表现,从另一个侧面看,也是
对软件开发设计的再确认。
八 面向对象的系统测试
? 具体测试内容包括:
·功能测试:测试是否满足开发要求,是否能
够提供设计所描述的功能,是否用户的需求都得
到满足。功能测试是系统测试最常用和必须的测
试,通常还会以正式的软件说明书为测试标准。
·强度测试:测试系统的能力最高实际限度,
即软件在一些超负荷的情况,功能实现情况。如
要求软件某一行为的大量重复、输入大量的数据
或大数值数据、对数据库大量复杂的查询等。
八 面向对象的系统测试
·性能测试:测试软件的运行性能。这种测试
常常与强度测试结合进行,需要事先对被测软件
提出性能指标,如传输连接的最长时限、传输的
错误率、计算的精度、记录的精度、响应的时限
和恢复时限等。
·安全测试:验证安装在系统内的保护机构确
实能够对系统进行保护,使之不受各种非常的干
扰。安全测试时需要设计一些测试用例试图突破
系统的安全保密措施,检验系统是否有安全保密
的漏洞。
八 面向对象的系统测试
·恢复测试:采用人工的干扰使软件出
错,中断使用,检测系统的恢复能力,特
别是通讯系统。恢复测试时,应该参考性
能测试的相关测试指标。
·可用性测试:测试用户是否能够满意
使用。具体体现为操作是否方便,用户界
面是否友好等。
·安装 /卸载测试( install/uninstall
test)等等。
八 面向对象的系统测试
?系统测试需要对被测的软件结合需求分析
做仔细的测试分析,建立测试用例。
前言
?什么是软件测试? 1983年 IEEE定义为:
使用人工或自动手段来运行或测定某个系
统的过程,其目的在于检验它是否满足规
定的需求或是弄清预期结果与实际结果之
间的差别。
前言
?现代的软件开发工程是将整个软件开发过
程明确的划分为几个阶段,将复杂问题具
体按阶段加以解决。这样,在软件的整个
开发过程中,可以对每一阶段提出若干明
确的监控点,作为各阶段目标实现的检验
标准,从而提高开发过程的可见度和保证
开发过程的正确性。
前言
?软件的质量不仅是体现在程序的正确性上,
它和编码以前所做的需求分析,软件设计
密切相关。
?软件测试的概念和实施范围应该包括在整
个开发各阶段的复查、评估和检测。由此,
广义的软件测试实际是由确认、验证、测
试三个方面组成
前言
?确认:是评估将要开发的软件产品是否是
正确无误、可行和有价值的。比如,将要
开发的软件是否会满足用户提出的要求,
是否能在将来的实际使用环境中正确稳定
的运行,是否存在隐患等。这里包含了对
用户需求满足程度的评价。确认意味着确
保一个待开发软件是正确无误的,是对软
件开发构想的检测
前言
?验证:是检测软件开发的每个阶段、每个
步骤的结果是否正确无误,是否与软件开
发各阶段的要求或期望的结果相一致。验
证意味着确保软件是会正确无误的实现软
件的需求,开发过程是沿着正确的方向在
进行。
一 前言
?测试:与狭隘的测试概念统一。通常是经
过单元测试、集成测试、系统测试三个环
节。
?确认 主要体现在计划阶段、需求分析阶段、
也会出现在测试阶段; 验证 主要体现在设
计阶段和编码阶段; 测试 主要体现在编码
阶段和测试阶段。
一 前言
?面向对象技术开发出的程序无需进行测试?
?面向对象程序的结构不再是传统的功能模
块结构,作为一个整体,原有集成测试所
要求的逐步将开发的模块搭建在一起进行
测试的方法已成为不可能。
二 面向对象测试模型
?面向对象的开发模型突破了传统的瀑布模
型,将开发分为面向对象分析( OOA),
面向对象设计( OOD),和面向对象编程
( OOP)三个阶段。分析阶段产生整个问
题空间的抽象描述,在此基础上,进一步
归纳出适用于面向对象编程语言的类和类
结构,最后形成代码。
二 面向对象测试模型
?
OOA Test:面向对象分析的测试
OOD Test:面向对象设计的测试
OOP Test:面向对象编程的测试
OO Unit Test:面向对象单元测试
OO Integrate Test:面向对象集成测试
OO System Test:面向对象系统测试
三 面向对象分析的测试
?面向对象分析( OOA)是 "把 E-R图和语义
网络模型,即信息造型中的概念,与面向
对象程序设计语言中的重要概念结合在一
起而形成的分析方法 ",最后通常是得到问
题空间的图表的形式描述。
三 面向对象分析的测试
? OOA直接映射问题空间,全面的将问题空间中实
现功能的现实抽象化。将问题空间中的实例抽象
为对象(不同于 C++中的对象概念),用对象的
结构反映问题空间的复杂实例和复杂关系,用属
性和服务表示实例的特性和行为。对一个系统而
言,与传统分析方法产生的结果相反,行为是相
对稳定的,结构是相对不稳定的,这更充分反映
了现实的特性。 OOA的结果是为后面阶段类的选
定和实现,类层次结构的组织和实现提供平台
三 面向对象分析的测试
?OOA对问题空间分析抽象的不完整,最终
会影响软件的功能实现,导致软件开发后
期大量可避免的修补工作;而一些冗余的
对象或结构会影响类的选定、程序的整体
结构或增加程序员不必要的工作量。
三 面向对象分析的测试
?对 OOA阶段的测试划分为以下五个方面:
☆ 对认定的对象的测试
☆ 对认定的结构的测试
☆ 对认定的主题的测试
☆ 对定义的属性和实例关联的测试
☆ 对定义的服务和消息关联的测试
三 面向对象分析的测试
? 1 对认定的对象的测试:
OOA中认定的对象是对问题空间中的结构,其他系统,
设备,被记忆的事件,系统涉及的人员等实际实例的抽象。
对它的测试可以从如下方面考虑:
1.1 认定的对象是否全面,是否问题空间中所有涉及到的实
例都反映在认定的抽象对象中。
1.2 认定的对象是否具有多个属性。只有一个属性的对象通
常应看成其他对象的属性,而不是抽象为独立的对象。
1.3 对认定为同一对象的实例是否有共同的,区别于其他实
例的共同属性。
1.4 对认定为同一对象的实例是否提供或需要相同的服务,
如果服务随着不同的实例而变化,认定的对象就需要分解或利用 继承性来分类表示。
1.5 如果系统没有必要始终保持对象代表的实例的信息,提
供或者得到关于它的服务,认定的对象也无必要。
1.6 认定的对象的名称应该尽量准确,适用。
三 面向对象分析的测试
?2 对认定的结构的测试
认定的结构指的是多种对象的组织方式,
用来反映问题空间中的复杂实例和复杂关
系。认定的结构分为两种:分类结构和组
装结构。分类结构体现了问题空间中实例
的一般与特殊的关系,组装结构体现了问
题空间中实例整体与局部的关系。
三 面向对象分析的测试
? 2.1 对认定的分类结构的测试可从如下方面着手:
2.1.1 对于结构中的一种对象,尤其是处于高层
的对象,是否在问题空间中含有不同于下一层对象的特殊
可能性,即是否能派生出下一层对象。
2.1.2 对于结构中的一种对象,尤其是处于同一
低层的对象,是否能抽象出在现实中有意义的更一般的上
层对象。
2.1.3 对所有认定的对象,是否能在问题空间内
向上层抽象出在现实中有意义的对象
2.1.4 高层的对象的特性是否完全体现下层的共
性
2.1.5 低层的对象是否有高层特性基础上的特殊
性
三 面向对象分析的测试
? 2.2 对认定的组装结构的测试从如下方面入手:
2.2.1 整体(对象)和部件(对象)的
组装关系是否符合现实的关系。
2.2.2 整体(对象)的部件(对象)是
否在考虑的问题空间中有实际应用。
2.2.3 整体(对象)中是否遗漏了反映
在问题空间中有用的部件(对象)。
2.2.4 部件(对象)是否能够在问题空
间中组装新的有现实意义的整体(对象)。
三 面向对象分析的测试
? 3 对认定的主题的测试
主题是在对象和结构的基础上更高一层的抽象,是为
了提供 OOA分析结果的可见性,如同文章对各部分内容的
概要。对主题层的测试应该考虑以下方面:
3.1 贯彻 George Miller 的 "7+2"原则,如果主题个数超过 7
个,就要求对有较密切属性和服务的主题进行归并。
3.2 主题所反映的一组对象和结构是否具有相同和相近的属
性和服务。
3.3 认定的主题是否是对象和结构更高层的抽象,是否便于
理解 OOA结果的概貌(尤其是对非技术人员的 OOA 结果读者)。
3.4 主题间的消息联系(抽象)是否代表了主题所反映的对
象和结构之间的所有关联。
三 面向对象分析的测试
? 4 对定义的属性和实例关联的测试
属性是用来描述对象或结构所反映的实例的特性。而
实例关联是反映实例集合间的映射关系。对属性和实例关
联的测试从如下方面考虑:
4.1 定义的属性是否对相应的对象和分类结构的每个现实实
例都适用。
4.2 定义的属性在现实世界是否与这种实例关系密切。
4.3 定义的属性在问题空间是否与这种实例关系密切。
4.4 定义的属性是否能够不依赖于其他属性被独立理解。
4.5 定义的属性在分类结构中的位置是否恰当,低层对象的
共有属性是否在上层对象属性体现。
4.6 在问题空间中每个对象的属性是否定义完整。
4.7 定义的实例关联是否符合现实。
4.8 在问题空间中实例关联是否定义完整,特别需要注意 1-
多和多 -多的实例关联。
三 面向对象分析的测试
? 5 对定义的服务和消息关联的测试
定义的服务,就是定义的每一种对象和结构在问题空
间所要求的行为。由于问题空中实例间必要的通信,在
OOA 中相应需要定义消息关联。对定义的服务和消息关
联的测试从如下方面进行:
5.1 对象和结构在问题空间的不同状态是否定义了相应的服
务。
5.2 对象或结构所需要的服务是否都定义了相应的消息关联。
5.3 定义的消息关联所指引的服务提供是否正确。
5.4 沿着消息关联执行的线程是否合理,是否符合现实过程。
5.5 定义的服务是否重复,是否定义了能够得到的服务。
四 面向对象设计的测试
?面向对象设计( OOD)采用 "造型的观点 ",
以 OOA为基础归纳出类,并建立类结构或
进一步构造成类库,实现分析结果对问题
空间的抽象。 OOD 归纳的类,可以是对象
简单的延续,可以是不同对象的相同或相
似的服务。由此可见,OOD不是在 OOA上
的另一思维方式的大动干戈,而是 OOA的
进一步细化和更高层的抽象。
四 面向对象设计的测试
?, OOD与 OOA 的界限通常是难以严格区分的。
OOD确定类和类结构不仅是满足当前需求分析的
要求,更重要的是通过重新组合或加以适当的补
充,能方便实现功能的重用和扩增,以不断适应
用户的要求。因此,对 OOD的测试,针对功能的
实现和重用以及对 OOA结果的拓展,从如下三方
面考虑:
☆ 对认定的类的测试
☆ 对构造的类层次结构的测试
☆ 对类库的支持的测试
四 面向对象设计的测试
? 1 对认定的类的测试
OOD认定的类可以是 OOA中认定的对象,也
可以是对象所需要的服务的抽象,对象所具有的
属性的抽象。认定的类原则上应该尽量基础性,
这样才便于维护和重用。测试认定的类:
1.1 是否含盖了 OOA中所有认定的对象。
1.2 是否能体现 OOA中定义的属性。
1.3 是否能实现 OOA中定义的服务。
1.4 是否对应着一个含义明确的数据抽象。
1.5 是否尽可能少的依赖其他类。
1.6 类中的方法( C++:类的成员函数)是
否单用途。
四 面向对象设计的测试
? 2 对构造的类层次结构的测试
为能充分发挥面向对象的继承共享特性,OOD的类
层次结构,通常基于 OOA中产生的分类结构的原则来组织,
着重体现父类和子类间一般性和特殊性。两者概念上的差
异。在当前的问题空间,对类层次结构的主要要求是能在
解空间构造实现全部功能的结构框架。为此,测试如下方
面:
2.1 类层次结构是否含盖了所有定义的类。
2.2 是否能体现 OOA中所定义的实例关联。
2.3 是否能实现 OOA中所定义的消息关联。
2.4 子类是否具有父类没有的新特性。
2.5 子类间的共同特性是否完全在父类中得以体现。
四 面向对象设计的测试
? 3 对类库支持的测试
对类库的支持虽然也属于类层次结构的组织
问题,但其强调的重点是再次软件开发的重用。
由于它并不直接影响当前软件的开发和功能实现,
因此,将其单独提出来测试,也可作为对高质量
类层次结构的评估。测试点如下:
3.1 一组子类中关于某种含义相同或基本相同的
操作,是否有相同的接口(包括名字和参数表)。
3.2 类中方法( C++:类的成员函数)功能是否
较单纯,相应的代码行是否较少。
3.3 类的层次结构是否是深度大,宽度小。
五 面向对象编程的测试
?典型的面向对象程序具有继承、封装和多
态的新特性,这使得传统的测试策略必须
有所改变。封装是对数据的隐藏,外界只
能通过被提供的操作来访问或修改数据,
这样降低了数据被任意修改和读写的可能
性,降低了传统程序中对数据非法操作的
测试。继承是面向对象程序的重要特点,
继承使得代码的重用率提高,同时也使错
误传播的概率提高。
五 面向对象编程的测试
?继承使得传统测试遇见了这样一个难题:
对继承的代码究竟应该怎样测试?多态使
得面向对象程序对外呈现出强大的处理能
力,但同时却使得程序内 "同一 "函数的行为
复杂化,测试时不得不考虑不同类型具体
执行的代码和产生的行为。
五 面向对象编程的测试
? 面向对象程序是把功能的实现分布在类中。能正
确实现功能的类,通过消息传递来协同实现设计
要求的功能。正是这种面向对象程序风格,将出
现的错误能精确的确定在某一具体的类。因此,
在面向对象编程( OOP)阶段,忽略类功能实现
的细则,将测试的目光集中在类功能的实现和相
应的面向对象程序风格,主要体现为以下两个方
面(假设编程使用 C++语言):
☆ 数据成员是否满足数据封装的要求
☆ 类是否实现了要求的功能
五 面向对象编程的测试
?1 数据成员是否满足数据封装的要求
数据封装是数据和数据有关的操作的
集合。检查数据成员是否满足数据封装的
要求,基本原则是数据成员是否被外界
(数据成员所属的类或子类以外的调用)
直接调用。更直观的说,当改编数据成员
的结构时,是否影响了类的对外接口,是
否会导致相应外界必须改动。值得注意,
有时强制的类型转换会破坏数据的封装特
性。
四 面向对象设计的测试
? 例如:
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被随
意访问。
五 面向对象编程的测试
?2 类是否实现了要求的功能
? 类所实现的功能,都是通过类的成员函数执行。
在测试类的功能实现时,应该首先保证类成员
函数的正确性。单独的看待类的成员函数,与
面向过程程序中的函数或过程没有本质的区别,
几乎所有传统的单元测试中所使用的方法,都
可在面向对象的单元测试中使用。
五 面向对象编程的测试
? 类函数成员的正确行为只是类能够实现要求
的功能的基础,类成员函数间的作用和类之间
的服务调用是单元测试无法确定的。因此,需
要进行面向对象的集成测试。
? 测试类的功能,不能仅满足于代码能无错运行
或被测试类能提供的功能无错,应该以所做的
OOD结果为依据,检测类提供的功能是否满足
设计的要求,是否有缺陷。必要时(如通过
OOD结仍不清楚明确的地方)还应该参照
OOA的结果,以之为最终标准。
六 面向对象的单元测试
?传统的单元测试是针对程序的函数、过程
或完成某一定功能的程序块。沿用单元测
试的概念,实际测试类成员函数。一些传
统的测试方法在面向对象的单元测试中都
可以使用。如等价类划分法,因果图法,
边值分析法,逻辑覆盖法,路径分析法,
等等,单元测试一般建议由程序员完成。
六 面向对象的单元测试
? 用于单元级测试进行的测试分析(提出相应的测
试要求)和测试用例(选择适当的输入,达到测
试要求),规模和难度等均远小于后面将介绍的
对整个系统的测试分析和测试用例,而且强调对
语句应该有 100%的执行代码覆盖率。在设计测
试用例选择输入数据时,可以基于以下两个假设:
1,如果函数(程序)对某一类输入中的一个
数据正确执行,对同类中的其他输入也能正确执
行。
2,如果函数(程序)对某一复杂度的输入正
确执行,对更高复杂度的输入也能正确执行。
六 面向对象的单元测试
?例如需要选择字符串作为输入时,基于本
假设,就无须计较于字符串的长度。除非
字符串的长度是要求固定的,如 IP地址字
符串。在面向对象程序中,类成员函数通
常都很小,功能单一,函数的间调用频繁,
容易出现一些不宜发现的错误。
六 面向对象的单元测试
? 例如:
? ·if (-1==write (fid,buffer,amount)) error_out();
该语句没有全面检查 write()的返回值,无意中断然假设
了只有数据被完全写入和没有写入两种情况。当测试也忽
略了数据部分写入的情况,就给程序遗留了隐患。
·按程序的设计,使用函数 strrchr()查找最后的匹配字符,
但误程序中写成了函数 strchr(),使程序功能实现时查找
的是第一个匹配字符。
·程序中将 if (strncmp(str1,str2,strlen(str1)))误写成
了 if (strncmp(str1,str2,strlen(str2)))。如果测试用
例中使用的数据 str1和 str2长度一样,就无法检测出。
六 面向对象的单元测试
?面向对象编程的特性使得对成员函数的测
试,又不完全等同于传统的函数或过程测
试。尤其是继承特性和多态特性,使子类
继承或过载的父类成员函数出现了传统测
试中未遇见的问题。 Brian Marick 给出了
二方面的考虑:
六 面向对象的单元测试
? 1,继承的成员函数是否都不需要测试?
对父类中已经测试过的成员函数,两种情况
需要在子类中重新测试,a)继承的成员函数在子
类中做了改动; b)成员函数调用了改动过的成员
函数的部分。例如:
假设父类 Bass有两个成员函数,Inherited()
和 Redefined(),子类 Derived只对 Redefined()
做了改动。 Derived::Redefined()显然
需要重新测试。对于 Derived::Inherited(),如
果它有调用 Redefined()的语句 (如:
x=x/Redefined()),就需要重新测试,反之,无
此必要。
六 面向对象的单元测试
?2,对父类的测试是否能照搬到子类?
援用上面的假设,Base::Redefined()
和 Derived::Redefined()已经是不同的成
员函数,它们有不同的服务说明和执行。
对此,照理应该对 Derived::Redefined()
重新测试分析,设计测试用例。但由于面
向对象的继承使得两个函数有相似,故只
需在 Base::Redefined()的测试要求和测
试用例上添加对 Derived::Redfined()新
的测试要求和增补相应的测试用例。
六 面向对象的单元测试
? 例如:
Base::Redefined()含有如下语句
If (value<0) message ("less");
else if (value==0) message ("equal");
else message ("more");
Derived::Redfined()中定义为
If (value<0) message ("less");
else if (value==0) message ("It is equal");
else
{message ("more");
if (value==88)message("luck");}
在原有的测试上,对 Derived::Redfined()的测试只
需做如下改动:将 value==0的测试结果期望改动;增加
value==88的测试。
七 面向对象的集成测试
? 传统的集成测试,是由底向上通过集成完成的功能模块进
行测试,一般可以在部分程序编译完成的情况下进行。
? 对于面向对象程序,相互调用的功能是散布在程序的不同
类中,类通过消息相互作用申请和提供服务。类的行为与
它的状态密切相关,状态不仅仅是体现在类数据成员的值,
也许还包括其他类中的状态信息。由此可见,类相互依赖
极其紧密,根本无法在编译不完全的程序上对类进行测试。
面向对象的集成测试通常需要在整个程序编译完成后进行。
? 面向对象程序具有动态特性,程序的控制流往往无法确定,
因此也只能对整个编译后的程序做基于黑盒子的集成测试。
七 面向对象的集成测试
?面向对象的集成测试能够检测出相对独立
的单元测试无法检测出的那些类相互作用
时才会产生的错误。基于单元测试对成员
函数行为正确性的保证,集成测试只关注
于系统的结构和内部的相互作用。面向对
象的集成测试可以分成两步进行:先进行
静态测试,再进行动态测试。
七 面向对象的集成测试
?静态测试主要针对程序的结构进行,检测
程序结构是否符合设计要求。现在流行的
一些测试软件都能提供一种称为, 可逆性
工程, 的功能,即通过原程序得到类关系
图和函数功能调用关系图。
七 面向对象的集成测试
? 动态测试设计测试用例时,通常需要上述的功能
调用结构图、类关系图或者实体关系图为参考,
确定不需要被重复测试的部分,从而优化测试用
例,减少测试工作量,使得进行的测试能够达到
一定覆盖标准。测试所要达到的覆盖标准可以是:
达到类所有的服务要求或服务提供的一定覆盖率;
依据类间传递的消息,达到对所有执行线程的一
定覆盖率;达到类的所有状态的一定覆盖率等。
同时也可以考虑使用现有的一些测试工具 来得到
程序代码执行的覆盖率。
七 面向对象的集成测试
? 具体设计测试用例,参考下列步骤:
1,先选定检测的类,参考 OOD分析结果,
仔细出类的状态和相应的行为,类或成员函数间
传递的消息,输入或输出的界定等。
2,确定覆盖标准。
3,利用结构关系图确定待测类的所有关联。
4,根据程序中类的对象构造测试用例,确认
使用什么输入激发类的状态、使用类的服务和期
望产生什么行为等。
七 面向对象的集成测试
?注,设计测试用例时,不但要设计确认类
功能满足的输入,还应该有意识的设计一
些被禁止的例子,确认类是否有不合法的
行为产生,如发送与类状态不相适应的消
息,要求不相适应的服务等。根据具体情
况,动态的集成测试,有时也可以通过系
统测试完成。
八 面向对象的系统测试
? 通过单元测试和集成测试,仅能保证软件开发的
功能得以实现。但不能确认在实际运行时,它是
否满足用户的需要,是否大量存在实际使用条件
下会被诱发产生错误的隐患。为此,对完成开发
的软件必须经过规范的系统测试。
? 开发完成的软件仅仅是实际投入使用系统的一个
组成部分,需要测试它与系统其他部分配套运行
的表现,以保证在系统各部分协调工作的环境下
也能正常工作。
八 面向对象的系统测试
?系统测试应该尽量搭建与用户实际使用环
境相同的测试平台,应该保证被测系统的
完整性,对临时没有的系统设备部件,也
应有相应的模拟手段。系统测试时,应该
参考 OOA分析的结果,对应描述的对象、
属性和各种服务,检测软件是否能够完全 "
再现 "问题空间。系统测试不仅是检测软件
的整体行为表现,从另一个侧面看,也是
对软件开发设计的再确认。
八 面向对象的系统测试
? 具体测试内容包括:
·功能测试:测试是否满足开发要求,是否能
够提供设计所描述的功能,是否用户的需求都得
到满足。功能测试是系统测试最常用和必须的测
试,通常还会以正式的软件说明书为测试标准。
·强度测试:测试系统的能力最高实际限度,
即软件在一些超负荷的情况,功能实现情况。如
要求软件某一行为的大量重复、输入大量的数据
或大数值数据、对数据库大量复杂的查询等。
八 面向对象的系统测试
·性能测试:测试软件的运行性能。这种测试
常常与强度测试结合进行,需要事先对被测软件
提出性能指标,如传输连接的最长时限、传输的
错误率、计算的精度、记录的精度、响应的时限
和恢复时限等。
·安全测试:验证安装在系统内的保护机构确
实能够对系统进行保护,使之不受各种非常的干
扰。安全测试时需要设计一些测试用例试图突破
系统的安全保密措施,检验系统是否有安全保密
的漏洞。
八 面向对象的系统测试
·恢复测试:采用人工的干扰使软件出
错,中断使用,检测系统的恢复能力,特
别是通讯系统。恢复测试时,应该参考性
能测试的相关测试指标。
·可用性测试:测试用户是否能够满意
使用。具体体现为操作是否方便,用户界
面是否友好等。
·安装 /卸载测试( install/uninstall
test)等等。
八 面向对象的系统测试
?系统测试需要对被测的软件结合需求分析
做仔细的测试分析,建立测试用例。