一个基于UML协作图的集成测试用例生成方法

发表于:2007-06-01来源:作者:点击数: 标签:测试用例方法生成集成
一个基于UML协作图的 集成测试 用例生成方法 王林章 (南京大学计算机科学与技术系,南京市汉口路22号419信箱,210093,南京)摘要: UML协作图描述了系统的一个协作中参与对象之间的结构关系和交互行为,确认它们是否被正确实现是集成测试的工作。本文提出
一个基于UML协作图的集成测试用例生成方法 王林章 (南京大学计算机科学与技术系,南京市汉口路22号419信箱,210093,南京)摘要: UML协作图描述了系统的一个协作中参与对象之间的结构关系和交互行为,确认它们是否被正确实现是集成测试的工作。本文提出了一个基于UML协作图生成集成测试用例的方法,将表示设计的协作图作为测试模型,并从中提取相关信息生成用于测试所描述的行为的集成测试用例。首先通过遍历每条消息的直接后继识别协作图中的表示用例实现的所有可能的场景路径,然后在遍历每条场景路径的过程中获取相应协作执行的路径条件、参数变量和预期方法调用序列,最后使用范畴-划分方法确定场景路径上的输入、输出、环境条件的合理组合作为覆盖该场景路径的测试用例,用于测试一个协作场景路径上的交互行为。该方法完全基于UML,集合了白盒方法和黑盒方法,生成了较少的测试用例覆盖所有的测试需求。本文将该方法应用于一个ATM建立会话的用例片断实现的实例,证明了其可行性和实用性,并提出了一个用UML设计的工具框架,以实现该方法的自动化,使得其可以方便地集成到使用UML的软件开发过程中。关键词:测试用例生成,集成测试,UML协作图,场景路径

中图分类号 : TP311   文献标识码 :    文章编号 :

An Approach to Generate Integration Test Cases based on UML Collaboration Diagrams Linzhang Wang, Xuandong Li,Guoliang Zheng (CS Department , Nanjing University, Hankou Road 22 P.O. Box 419, 210093, Nanjing) Abstract: UML collaboration diagrams represent the structure relationship and interactive behavior of the objects involving in a collaboration of the software system, whether they are correctly implemented or not can be validated by integration testing. This paper propose an approach to generate integration test cases based on UML collaboration diagrams, take collaboration diagram as test model, from which we can extract information to generate integration test cases for testing the behavior. Firstly, the method identifies all the scenario paths in the diagram which represent use case realization by traverse the direct successors of each message. Then it selects and traverses each scenario path to get the method call sequence, path condition and parameters. Lastly, it applies category partition method to generate rational combination of input parameters, environmental conditions, as well as the corresponding output and method call sequence, to form a test case for each scenario path, thus we can test the interactive behavior of the software. This method completely base on UML, combine white-box and black-box test method to generate fewer test cases to test the gray-box behavior. In this paper, we apply this approach to an example of constructing sessions between cardholder and the bank through ATM, proving its feasibility and practicability, also propose a corresponding tool framework to facilitate its automation, thus to easily be deployed into the UML –based software development process. Keywords: test cases generation, integration testing, UML collaboration diagram, scenario path 1、引言 面向对象的技术因为能够解决传统程序设计语言的问题,自提出后,一度成为研究热点,事实上采用面向对象技术减少了不少错误的发生,对于提高软件质量起到了很大的作用,但是面向对象技术本身在任何情况下都不会排除软件测试的动机,同时面向对象语言的本质特征,如继承、封装、和多态等,也带来了新的故障风险,并给软件测试提出了新的挑战。[1,2,9] 区别于传统软件的功能分解,面向对象软件是通过合成来构造软件的,因而集成是面向对象软件开发中最重要的工作,面向对象软件构造过程中有的不同层次的集成,包括:从方法到类的集成,类通过继承集成,类通过容器集成,类到组件的集成,组件到应用系统的集成。在面向对象的迭代式增量开发过程中,通过不断的集成产生系统的可执行的版本,但每一个集成的环节都可能引入错误,导致软件中存在缺陷,为了能够发现软件集成中的问题,面向对象软件的集成测试非常重要。[4] 对于传统软件的集成测试,可以根据设计阶段形成的功能分解树,采用自顶向下或自底向上逐步测试用经过测试的单元组装成系统的过程中有无错误。[3]而面向对象软件采用的是通过组合实现系统的功能,没有一个功能分解树可用,所以传统的基于功能分解的集成测试策略不适合面向对象软件。要检验最终实现中各种集成是否与设计的集成一致,则需要对每一个集成层次进行测试,而这里的集成分为结构集成和行为集成,所以面向对象软件的集成测试包含结构集成测试和行为集成测试。结构集成测试主要测试类的继承、类的容器、类的接口、组件的接口中有无错误;行为集成测试主要是类内方法交互、类间方法交互、组件间交互是否被错误地实现。测试工作的核心主要是生成测试用例,在面向对象软件开发过程中系统的规约、设计、代码是生成测试的信息来源,是软件在其生命周期不同阶段的变体,当然规约、设计、代码在每一阶段的测试中都起相应的作用,特别地,系统规约是生成系统测试的测试用例的基础和系统测试的检验依据,软件代码是生成单元测试用例的基础和单元测试的检验依据,系统设计是生成集成测试用例和集成测试的检验依据。系统的设计信息有助于理解系统功能和结构,设计模型包含规约和程序结构的信息,同时也描述了系统的相应功能片断的行为,因此也被称为灰盒。可以结合白盒测试黑盒测试方法,从设计信息生成集成测试用例,测试设计模型表示的软件系统的灰盒行为。 UML是面向对象系统分析、设计的标准的建模语言,自从在1997年成为建模语言事实上的标准后,就得到学术界的推崇和工业界的支持,使得UML广为使用,基于UML的方法和实用技术的研究成为将来的发展趋势。UML对面向对象软件开发全生命周期的支持也使得软件开发人员优先用它来描述系统。[8]正像集许多优点的面向对象技术不能免除软件测试一样,使用UML进行面向对象软件开发,在提高软件质量的同时,仍然需要测试来确认软件分析、设计、实现的一致性和正确性。同时基于UML开发的软件系统,软件开发的分析、设计阶段工作成果多为各种模型图,系统的可用信息都在这些模型图中,给信息的提取带来了新的问题,从而也给测试带来新的课题。对测试而言,原先的基于规约或者是基于程序的方法都不能直接使用,对基于UML模型的测试,要将问题转换到原来传统测试方法可以处理的问题空间中加以解决,转换工作主要解决信息提取问题,然后用常规测试方法生成测试。面向对象的软件中,对象通过交互来实现行为,UML的交互图[6,7]是描述一组对象间的结构关系和交互行为设计的最佳选择,主要有顺序图和协作图两种,顺序图关注全局的时序,协作图关注协作对象之间的关系,本文主要研究协作图。UML协作图描述了系统的一个协作中参与对象之间如何交互,集成测试正是要验证这些对象是否正确交互,所以我们研究基于UML协作图的集成测试用例生成方法。本文中我们使用UML协作图作为系统功能片断的高级描述,用来作为生成测试的基础,使得在系统设计阶段一开始就可以计划集成测试阶段的测试。在软件开发早期准备软件测试,在软件的系统分析、设计阶段,利用每一阶段的人工制品(artifact)生成软件测试各个阶段所需的测试用例,在代码阶段结束后便可以开始测试工作,而且对分析设计模型进行分析的同时也能发现分析、设计本身的缺陷,以便及时排除,以防缺陷随着软件开发过程的进展而被放大。由于UML在工业界的使用越来越普遍,而相应支持在分析设计阶段基于模型生成测试用例的实用方法和支持工具还不多见。我们希望能够研究出仅从UML分析、设计模型图自动生成测试用例的方法,而且不需要使用者的除UML外其他方面专业的知识,能够实现自动化而不增加用户额外的工作量,这样的测试方法容易被已经使用UML的工业界采用。[8,10] 本文研究如何通过面向对象软件设计阶段的UML协作图选择合适的集成测试用例的方法,第2部分对协作图的语法和语义作了详细的介绍,并回顾了测试模型、协作集成测试模式、协作故障模型等知识;第3部分对基于协作图生成测试用例的方法作了总体介绍,详细描述了从协作图生成测试用例的具体算法和支撑工具框架原型,第4部分是相关工作的介绍,最后是结束语和将来工作的构想。

2、协作图与集成测试
2.1协作图的语法和语义
UML协作图[7]就是用来表示一组通过交互来实现某些行为的对象,可以用来可视化、详细描述、构造和文档化一个特定的对象群体的动态方面,也可以用来按交互中的角色及其关系对一个用例的特定的场景或控制流的实现进行建模。协作图描述了特定行为的参与对象的静态结构,以及参与对象之间的动态交互,可以用于不同的规约抽象级别,规约级协作图表示了类元角色、关联角色和消息,表示对象之间的可能的关系,而实例级协作图表示对象、链和激励,表示特定对象之间的关系。两者都描述了协作参与者之间的结构关系。如果要表示可能事件,一般用规约级协作图,其中没有条件和循环,实例没有取值范围或有许多可能的路径。实例级协作图用于描述属性或参量有具体的值的对象和链,可变大小多重性的对象和链的具体数目,或者是执行中的分支或循环的特定选择。协作图可以用来表示用例的实现或操作的实现,描述操作和用例的执行实现所处的语境、交互中行为序列。当协作图用于表示用例的实现时,只描述外部可见的动作及其顺序,用对象之间的消息交换来描述一个用例实现的场景。当协作图用来表示一个对象的操作的实现时,提供了更详细的信息,如操作的参数及其用途、参与变量的特征、关联上的约束、操作实现过程中对象的创建和破坏等。本文主要研究用于表示用例实现的实例级协作图,下面介绍实例级协作图符号及其语义。
协作描述了在一定的语境中一组对象以及用以实现某些行为的这些对象之间的相互作用。协作由静态部分和动态部分组成,静态部分描述在协作实例中对象和链可能担任的角色,是角色集合和其间关系,这些关系定义了结构方面的内容,动态部分是一个消息集合,包括一个和多个动态交互,表示在执行计算过程中不同时间里协作中的消息流, 这些消息定义了行为方面的内容。角色表示协作中对象和链的目的,类元角色定义了参与协作执行的对象在一个协作中扮演的角色,关联角色定义了一个类元角色和其他角色之间的关系,是参与协作执行的关联的描述,关联角色是链的子集,链是两个或多个对象之间的单向连接,是关联的实例。对象必须是位于关联相应位置的类的直接或间接实例。关联是两个或多个特定描述其实例间连接的类元之间的关系,参与关联的类元在关联内有有序的位置。在运行时,对象和链与协作中的角色绑定,在不同的协作中一个对象可以绑定到一个或多个角色。
交互是由在一个实现特定目标的协作内一组对象之间通信序列组成的行为规约。每个交互包含消息的偏序集,这些消息由类元角色通过关联角色交换。消息是激励的规约,是发送者和接受者之间的通信。消息指定了发送者对象和接受者对象扮演的角色,说明发送者对象对接受者对象应用何种操作。激励是传递消息期望发生的两个对象之间的通信,激励导致一个操作被激活、发出一个信号、导致一个对象被创建或终止。
本部分介绍一个客户通过ATM上验证用户卡和PIN有效性、建立会话的用例片断[9]的实例级协作图,如图1所示。协作图上存在条件消息说明考虑到许多不同的用例场景,涉及到多个对象之间的交互,其中每一个场景都对应协作图上的一条执行路径,这正是测试所要尝试的。图2表示了在这个协作中参与对象相应的类图。

一个描述用例实现的实例级协作图上用于建模的元模型包括:类元角色名、关联角色名、对象符号、链接符号、消息符号、链上的约束等。对象框能够表示参与协作中交互的对象,链表示这些对象之间的结构关系,消息的箭头形状表示协作对象间的通信模式和对象的执行特征, 消息标签表示对一个对象的操作调用的允许顺序的实例、操作的语义。在实际的建模活动中有些元素并不在模型上反映,例如图1的协作图只表示了协作中参与的对象和对象之间的消息,这是表示对象交互的最小元素集。本文关注协作图表示的动态行为的测试,前面提到协作图上表示交互的主要元素是消息,下面详细介绍消息。
协作图中的消息用带有消息标签的箭头表示,附在连接发送者和接受者的链上,链用于访问目标对象,箭头沿着链指向接受者,一个链上可以有多个消息,沿着相同或不同方向传递,消息的相关顺序由消息标签中的顺序号表示。按照UML1.5[5]中提出消息箭头有三种形状表示对象之间的通信方式和控制流类型:实线实心箭头表示同步消息,用于表示过程调用和嵌套控制流,每次调用增加一个嵌套层次;刺状箭头表示平面控制流,是异步通信,无嵌套,表示前驱-后继关系,指向下一步骤;虚线刺状箭头表示从过程调用返回。图1中的消
 
图1 ATM建立一次会话的实例的协作图
息都是带有刺状箭头的实线,表示前驱/后继关系。消息标签说明发送的消息、发送的条件、由消息激活的方法、相应的参量和返回值,以及交互中的消息顺序,包括调用嵌套、迭代、分支、并行和同步,完全格式消息标签的语法[5]中有详细的定义。其语法如下:
[predecessor][guardcondition][sequence-expression][return-value-list]:=message-name(argument)
[predecessor]表示前驱,在协作中前驱是用逗号隔开的顺序号列表,并后跟“/”;[guardcondition]表示线程同步的卫式条件;[sequence-expression]表示顺序项列表每一项表示交互中的一个嵌套层次,如果所有的控制并行则无嵌套;整数表示过程调用中的相邻高层中的消息的顺序,同一整数项中的不同消息在嵌套层是顺序相关的,同一前缀的消息顺序号构成序列。循环表示条件或迭代执行,表示根据条件执行零个或多个消息;[return-value-list]在有返回值的情况下表示消息返回值的名称,名称之间用逗号隔开,可以作为后续消息的参量;message-name 表示目标对象中引发的事件名称,可以用不同的方式实现,如操作调用;Argument 是消息引发的方法的参量列表。
 
图2 图1 ATM用户验证的类图
    消息上的条件增加了消息的表达能力,也增加的消息复杂度,消息上的条件有几种形式:在一个新的调用层次开始,如图1中消息标签4.1[isMemberCard]feeAmount:=getfeeAmount()所示:4.1表示一个新的调用序列,条件成真时该层次的消息顺序发送,否则都不发送;在顺序发送的消息上,例如消息1.3中,[!isATMCard]条件表示二值条件,条件成真时其后的消息eject()执行一次,否则不执行,对其他消息没有影响;在一个表示迭代的嵌套调用消息开始,如消息3.1.1表示了一个迭代执行多个消息的情况,根据validPIN和n的取值可能发送1或2次消息。
这些协作图上的模型元素所表示的软件系统的不同方面的信息,都是系统的本质信息,需要在软件从设计到实现过程中必须保持的,因而软件实现中的行为的本质方面都会在设计中表示,所以可以从设计表示中获取行为方面的信息,用于确认软件实现中是否正确实现。 
2.2场景路径
一个表示用例实现的协作图实现了用例的不同事件流,包括正常流和异常流,每个事件流称为一个场景,这些场景都被相应的协作图实现。一个协作图所表示的协作正是从一个外部事件触发开始,在参与协作的对象之间完成一系列的交互,最后正确的协作结束时都导致一个外部输出 ,对应于一个实际场景,也是一个线程执行的路径。要找到这些路径,一般的方法是将协作图转换为流图,然后在流图上使用图遍历的方法达到路径覆盖从而得到所有的路径。本文为了避免复杂流图的转换和不可行路径的遍历开销,试图直接从协作图上获取这些路径。我们从Paul C. Jorgenson[4]定义原子系统功能(ASF)和方法/消息路径(MM-path)得到启发,本文定义了一个场景路径(scenario-path):
定义 场景路径(scenario-path,s-path)是协作图上从一个没有前驱消息的消息开始,沿着消息的偏序执行序列,到达一个没有后继的消息结束的由消息相连的方法执行序列。
由于面向对象软件的事件驱动特性,软件的执行由事件开始,反映场景执行的场景路径由一个外部事件触发的消息(没有前驱消息)开始,表示路径入口,通过消息传递访问协作图中参与一个协作场景实现交互的对象的方法序列,达到一个引发端口输出事件的方法且该方法自己不再发出新的消息(没有后继)结束,到达路径出口,这时系统处于静止状态,等待另一个系统级端口输入事件开始进一步的处理。一个场景路径的线程的执行是一个原子执行,场景路径表示了协作图中的一个场景的线程执行的完整的踪迹,也是参与协作的对象之间的交互的踪迹,消息的传递激活对象方法的执行是对象之间控制流的转移,而路径中通过消息激活的方法调用的参数定义和使用、对象的创建、使用和撤销明显表示了一条在控制流上执行的数据流。
由于协作图在表示用例实现时,协作图上的场景路径是从第一条入口消息开始到所有能触发端口输出事件或没有后继消息的出口消息之间的所有可能的消息流。要获取场景路径上的消息流,可以通过消息之间的偏序关系以及决定消息流分支和循环的条件来实现。回顾协作图上消息及其顺序号的定义,整数表示过程调用中相邻高层中的消息顺序,同一整数项下的不同消息是表示一个前驱-后继式的平面控制流,嵌套的消息顺序号表示过程的调用控制流。消息顺序号隐含地表示了消息之间的偏序关系,因此可以在协作图上提根据消息的发送条件及其顺序号来跟踪场景路径。协作图中通过消息顺序号跟踪消息执行的顺序比顺序图中通过自上而下的生命线跟踪消息执行的顺序困难得多,但由于协作图更容易表示对象之间的动态连接关系,协作图不关注全局的消息执行顺序,只关注一个场景的执行路径上的消息顺序,这为我们识别场景路径提供了方便。协作图上的分支和循环导致了许多可能的路径,极端的情况下路径的数目可能到达一个庞大的数字,我们要达到协作图上的路径覆盖,采用简单的方法达到判定/循环覆盖。我们先将循环消息看作条件消息,在遍历场景路径的过程中,访问一条消息后,先找出该消息可能的直接后继,然后采用深度优先的方法选择一个直接后继继续遍历,当到达一个没有后继的消息时,就完成一个场景路径的遍历,回溯到下一个直接后继,继续遍历,只到所有的直接后继都已被访问,则完成了所有的场景路径的遍历。这样我们实现每条消息至少遍历一次,每个条件分支都至少遍历了一次,也避免了路径的穷尽覆盖。然后处理协作图上的循环,一般是给出绕过循环、循环一次、循环最多次以达到循环路径的覆盖。对于存在分支和循环的场景路径,例如图1所示的协作图上有7个条件判断和一个最大次数为2的循环,可能的路径有2*2*2*2*3*2*2*2=192条,但由于有5个条件判定各有一个分支直接导致场景路径结束,所以实际的场景路径应为1+1+1+1+1+3*2+2=13条,这13条场景路径对应相应软件功能的13个执行场景。
我们在协作图上遍历生成场景路径的同时,很容易基于路径覆盖准则获取相应场景执行过程中的控制流和数据流、覆盖路径的条件,然后可以确定每一路径所需要的输入和状态条件,当满足所有路径条件时线程就会沿着该路径执行,这正是我们定义集成测试用例所需要的信息,因此我们考虑将场景路径作为基于协作图的集成测试的基础。下面我们分析协作图表示的协作在实现中通过参与者之间的集成完成时可能发生的故障,这样便于我们研究针对检错为目的的测试。 
2.3基于协作图的协作集成测试模式
协作图上描述的软件系统的消息的错误实现可能导致协作中表现的行为发生偏差,从而使最终实现与设计不一致,偏离软件规约规定的功能。例如由于消息名的编码错误、错误的参数、不正确的参数值、不正确的或缺少输出以及非预期的运行时绑定导致的错误方法调用;消息前驱约束实现错误导致发送者对象发送违反接受者对象前提条件的消息或者发送者对象发送违反接受者对象的顺序约束的消息;消息的发送者或接受者对象错误导致错误的对象和消息的绑定;参与者缺少功能或特征导致错误的对象引起正确的异常、正确的对象产生错误的异常。所以链上的消息箭头和约束、消息标签、对象等协作图上的元素未按设计正确实现会导致最终的软件与设计不一致,如果协作图的实现中存在错误,肯定在协作图至少一条路径上,要达到该错误,在未知该错误在那条路径上时,只能通过协作图上选择所有可能的执行路径,并导出能够跟踪这些路径的测试用例,并用它们来执行软件,来确定错误在哪条路径上,即哪条路径被错误实现了,从而可以调试软件,改正错误,以保证实现与设计一致。
这些可能发生的错误都是在参与协作的对象之间交互时发生,也就是系统在通过不同类的对象的方法之间集成实现系统的行为时发生,这种错误通常由集成测试来发现。软件集成测试有几种常用的集成测试模式(integration testing pattern):一次性组装、自底向上集成、自顶向下集成、协作集成、基干集成、层次集成等,但是考虑到面向对象软件时有的模式不一定有用,在面向对象的系统中,很难找到一个控制的层次结构,使得方便定义自底向上集成、自顶向下集成、层次集成等策略。在面向对象的环境中我们可以通过基于线程或基于使用的测试技术测试类的交互。这里交互的类可以是单个类及其实例、类簇、组件、子系统或系统。用协作图描述的系统协作在集成测试时,协作集成是最佳的测试模式[9],通过在协作中参与的组件来决定集成测试所有参与的对象。基于协作的集成测试需要检测协作的参与者之间的接口和交互,通过协作组织集成。每次处理一个协作,直到协作图上的所有协作都被测试。当所有构件的接口和构件之间的交互都测试完时集成测试完成。协作中包括的构件按照在一个处理线程、一个事件-响应路径来选择,要求系统中每个构件之间的消息已经被至少测试一次。我们前面定义场景路径正是一个线程完成协作执行的一个事件-响应路径,所以可能发生的错误会出现一条或多条场景路径上。
测试模式是一个测试策略,是建立在测试模型基础上的,而测试模型应该是被测软件系统的一个表示,能够从测试模型上获取测试需求,导出测试规约,从而生成测试用例。协作图是对象、组件、子系统、系统范围需求的良好来源,对系统的一个有限片断来说,提供了实现的抽象视图,它通常是过多或过少细节之间的一个良好的折中,可以用于在不同抽象级别和粒度级别建立软件系统的模型。由于协作图是描述的对象之间的交互,而系统的功能正是通过这些交互实现的,所以要考虑将设计描述的协作图作为生成集成测试的测试用例的测试模型。协作图上包括了对象间传递的消息及其顺序,这正是设计级的控制流和数据流信息,以往数据流和控制流只能从程序源码中分析得到。数据流和控制流对生成测试有很大的作用,所以我们利用协作图生成测试用例,就是要从协作图上提取出相应的数据流和控制流信息,利用传统的数据流、控制流生成测试用例的方法,生成可用于集成测试的测试用例。所以本文使用作为系统设计描述的协作图作为测试行为的测试模型,避免重新构造测试模型或者进行模型转换。
2.1中分析了协作图中描述的信息,这也是作为测试模型的协作图中包含的对生成测试用例有用的信息,这些信息是规约在转变成实现时必须保持的,这些信息也是测试时要确认在软件实现中是否正确保持的设计信息,因此这就是测试工作第一步要获取的测试需求。测试需求的正确实现要求也就是测试规约,它规定了能让软件执行并正确反应测试需求的测试用例。如果我们能够用足够的测试用例执行了程序,并证明协作图上所有测试需求都在软件中正确保持了,就可以说测试充分了,本文主要关注协作图表示的系统的动态交互行为,而协作图上用于表示交互行为的主要是消息及其偏序序列,所以本文研究的测试方法的充分性准则是协作图上所有的消息及其偏序关系都被测试用例覆盖。表1中的协作图的集成测试需求说明至少有一个测试用例测试对应的关系来检查测试需求是否满足。
符号 关系 集成测试需求
实线实心箭头 扁平控制流   发送者与接受者之间的偏序
实线刺状箭头 过程调用                    
条件过程调用                                                   

迭代过程调用                
递归过程调用             发送者发送消息到接受者并返回
发送者发送消息到接受者并返回,
发送者不发送消息到接受者 
发送者重复发送消息到接受者并返回
发送者发送消息到自己
虚线刺状箭头 从过程调用返回 可不考虑
表1 消息对应的集成测试需求
一个场景路径上由消息激活的方法序列表示了我们要测试的行为,路径上对象间的消息传递描述了要实现相应的功能对象间必要的交互,协作图上场景路径的构造能够满足表1描述的协作图对应的集成测试需求,这样我们就可以把问题转换到满足协作集成测试需求的场景路径的分析和处理上。我们在协作图上遍历生成场景路径的同时,很容易基于路径覆盖准则获取相应场景执行过程中的控制流和数据流、覆盖路径的条件,然后可以确定每一路径所需要的输入和状态条件,当满足所有路径条件时线程就会沿着该路径执行,测试用例的定义需要满足路径条件的特定输入和状态。为了确定测试用例的值,需要分析每条路径上的谓词,从第一个谓词开始,选择满足相应路径条件输入和状态值。直到完成所有的路径条件,最后确定每个测试用例的预期结果,包括方法调用序列。第3部分详细描述从协作图构造场景路径,然后基于场景路径生成测试用例的方法。

3、基于协作图生成集成测试用例的方法
3.1研究假定
为了有针对性地解决从协作图生成测试用例的问题,本文作出如下假定和要求:
(1)假定协作图描述的协作与用例图描述的规约是一致的。模型本身的验证是通过非形式化的复审和形式化的模型检验方法进行的,已超出本文的研究范围;如果协作图上的场景路径集不能覆盖所有消息,则说明协作图本身有错误;
(2)假定系统中的对象都是自行开发的,不包括第三方组件对象,文中的对象可以是不同粒度的对象(类的实例、类簇、组件、子系统、系统),也就是说我们在分析任意对象或类时,在必要的情况下都可以获取其规约和内部详细设计信息,包括功能和结构信息;对于第三方组件的集成测试,[13][17]介绍了详细的测试方法;
(3)我们研究的测试是针对检错进行的,确认软件是否正确实现了设计,协作图上的结构关系是否被正确实现,[15]中已有相应的静态检验方法,所以本文只研究动态交互行为的测试;
(4)本文为了明确解决问题,假定消息类型只有普通消息、条件消息、循环消息,而且只存在顺序循环,不存在嵌套循环。
3.2方法概述
基于协作图的集成测试(Collaboration diagram-based Integration Testing, CIT )方法集合了传统的白盒测试方法黑盒测试方法,用于测试协作图中参与协作的对象之间通过消息的交互,对每个协作图处理一次,得到相应的测试用例集。首先分析协作图,提取协作图中表示的所有元素,根据消息的顺序号和消息的条件,找到每一条消息的直接后继消息,然后根据场景路径的定义,使用深度优先方法遍历消息及其直接后继直至到达无直接后继的消息从而生成场景路径,然后回溯到没有被访问的直接后继,重复上述方法找到所有的场景路径;在访问消息获取场景路径的同时,获取该路径的方法调用序列、参数和路径条件,将这些集成测试的关键因素用范畴-划分方法定义为方法序列、环境条件、系统输入、系统输出等范畴,结合该协作片断的用例规约和类图中的定义生成这些范畴的可能选择,然后结合路径约束条件在这些范畴的划分中确定选择项的合理组合,这样我们就等到了该场景路径完整的测试用例,包括外界输入、交互输入、预期方法调用序列、后条件、预期输出。对协作图中的所有场景路径都构造了测试用例,就形成了协作集成测试用例集。这样在实际执行集成测试时不但可以直接观察到系统级的输入作用下协作实现过程中的实际输出,还能够通过动态插装方法在代码中加入不影响软件功能的观察代码[15],使测试人员能够观察到实际协作执行时的方法调用序列和数据流的定义和使用,然后通过比较最终系统实际执行时输出与预期输出的一致性决定该协作实现的功能是否正确,通过比较应该发生的方法调用序列和实际执行时观察到的方法调用序列是否一致,确定协作表示的交互行为是否正确,从而从整体上对协作图描述的系统行为的实现是否与设计一致,从而完成协作的集成测试。
本方法可以以增量的方法进行,最终生成的测试用例的具体程度,与相应UML模型图的设计精化程度相关,因为协作图描述的场景的详细程度与测试用例的表达能力直接相关。
3.3 UML协作图生成测试用例的算法描述
本文的方法能够从协作图规约文档直接生成测试用例,主要描述分析协作图规约文档提取集成测试需求信息并生成消息后继表的算法UMLspecificationparser(),然后为每个消息确定其直接后继消息的findsuccessor()算法,根据消息后继表遍历所有场景路径获取测试用例规约信息的spathgenerator()算法,以及从测试用例规约使用范畴划分方法确定测试用例输入值、预期输出值、预期输出行为的算法testcasegenerator()。UMLspecificationparser()算法从协作图从获取集成测试需求信息是通过对UML协作图规约的文本文件(如Rational Rose 的MDL文件)进行分析完成的[11],在我们的工具中实现相应的功能,本文对分析算法不作详细描述。我们用邻接表定义消息后继列表,将分析结果信息按消息顺序号升序记录到messagelist的表头中,以便下一步处理。我们定义消息后继列表如下:
messageitem{
mid:string;//消息顺序号
mguardcondition:string;//消息卫式条件表达式
mlabel:string;//消息标签
msender,mreciever:object;// 消息发送者对象,消息接收者对象
mmethod:method;//消息激活的方法
mtype:[flat flow, procdure call, call return];// 根据消息的箭头及线型划分的消息类型
link:pointer of msuccessor;
}
msuccessor{
mid:string;//后继消息顺序号
mscondition:string;//选择该后继的条件表达式
next:pointer of msuccesor
}
messagelist:messageitem[n];
findsuccessor()算法为消息生成直接后继列表的并记录到消息的后继链表中,描述如下:
findsuccessor(messagelist){ //找到所有消息的所有可能后继和每个后继条件
//输入:消息后继表messagelist
//输出:消息后继表messagelist
//出口准则:所有消息都处理完
for i:=1 to n do {
if i= =n 或者messagelist[i]为端口输出事件触发消息
   messagelist[i].link=nil;i:=i+1; //最后消息或触发端口输出事件的消息无后继消息 
else{
if  messagelist[i+1]是普通消息
则messagelist[i]的直接后继为messagelist[i+1];
else{
k:=1;
do while  messagelist[i+k]是条件消息{
messagelist [i+k]是messagelist [i]的直接后继,且条件为messagelist [i+k]的条件取真
if messagelist [i+k]是循环或嵌套层次的第一个消息{
t:=该层次的消息数;messagelist [i+k+t]是messagelist [i]的直接后继;
条件为messagelist [i+k]的条件取假; k:=k+t;}//条件取假时循//环或嵌套内的消息都不发送
else{
messagelist [i+k+1]是messagelist [i]的直接后继;
条件为messagelist [i+1]的条件取假; k:=k+1;//不发送
}endif
}enddo
}endif
i:=i+1;
}endif
}endfor;
}endfindsuccessor;
spathgenerator()通过访问消息后继表中消息及其直接后继生成场景路径,在遍历场景路径时同时记录路径上相应的控制流和数据流信息,执行完毕得到一个场景路径集spath相应的控制流数据流测试规约。其算法描述如下:
s-pathgenerator(m:msuccessorlist){
//输入:messagelist; (消息后继表)
//输出:spath;(场景路径集)
spath{
sid:integer;//场景路径顺序号
pathcondition: list of gardcondition; //场景路径的实现条件
mlist:list of message;//场景路径上的消息流列表
parameters:list of variable;//场景路径上定义和使用的变量列表
userinputparameters: list of variable; //场景路径上外界输入参数列表
methodsequence:{objectname,methodname,next};场景路径上由消息激活的方法序列
}[n];
i,j:integer;
i:=1; j:=1;
Sid:=j;//场景路径序号
//递归访问消息及其直接后继
访问消息m,在消息标签中取出并记录返回值、参数、调用的对象方法;
记录消息条件到路径条件中;
if m的后继消息为空
{ 一条场景路径结束;j:=j+1;return;}//回溯到m[i]的直接前驱继续
else{
k:=1;
while m.link<>nil do { //m的后继消息列表不空
successor:=m.link;
spathgenerator(successor) //深度优先遍历该消息及其后继消息
m.link:=successor->next;//下一后继消息;
}endwhile
}endif;
}endfind;
testcasegenerator()选定遍历一个场景路径过程中生成的控制流和数据流,定义相关范畴,生成测试用例的规约。消息激活的方法序列正是我们要测试的对象间的交互,是软件执行时表现出来的对象之间的控制流传递行为,是对象之间通过消息交互的结果,定义为交互范畴Interaction Category;输入参数列表为测试该场景时外界的输入,定义为输入参数范畴input parameter Category;我们通过对参与协作对象的类图的分析,以及用例描述,可以获取我们所研究的交互行为定义、输入参数的定义、其他影响消息执行的变量的定义、系统环境条件的定义等,从而可以获取这些系统环境条件、输入参数、方法行为的可能选择,然后结合。
利用范畴-划分思想,用相应场景路径的路径条件和加在消息上的约束、以及系统本身的属性约束来限定这些选择,排除无意义和有冲突的值,然后通过这些不同的范畴的不同选择的可能组合作为一个场景路径的测试用例,这样每个场景路径生成一个集成测试用例。具体算法描述如下:
Testcasegenerator(){
//输入:spath[n]
//输出:tcsuite[n]{ envirnmentpara,input(inputpara,paravaliue),expectoutput,postcondition}
i:integer;
for i:=1 to n do {
tcsuite[i].postcondition:=spath[i].pathcondition;
tcsuite[i].environmentpara:={满足路径条件的环境条件}
tcsuite[i].input.inputpara=spath[i].userinputsparamenters;
选择对本场景路径条件有影响的参数确定其可能的取值;
tcsuite[i].input.paravalue={符合路径条件的输入参数可能的取值};
取出spath[i]的方法激活序列,分析每一个方法的定义,确定其可能的行为,选择符合场景路径条件的行为,并将方法序列的执行过程的输出序列存到tcsuite[i].expectoutput中;
i:=i+1;
}endfor;
}endtestcasegenerator;
为说明问题,我们选一条最长路径spath[5](消息序列为:1.1,1.2,2.1,2.2,2.3,4.1,4.2,4.3,5)来演示使用上述方法生成覆盖该路径的测试用例的过程。,从该路径获取相关范畴如下:
Tcsuite[5]
Pathcongdition:!notATMCard, !isStolen, !accountClosed, validPIN&&n=1,!declineFee
Environmentcondition:
ATM卡,非成员卡,卡没有被盗,帐户没有关闭
parameter category:
inputPIN     //影响validPIN  
123456 [property validPIN][if !notAtmCard]
564821 
123258
……..
deClineFee     //影响deClineFee
T   [property declineFee][if !isMemberCard]]
F
interaction behavior category:
session.beginSession(),     
插卡事件创建session对象
cardSlot.isATMCard(),
判断是ATM卡,读取卡号,定义cardNum,notATMCard=F[if !notATMCard]
判断不是ATM卡,notATMCard=T    
screen.prompt(),
屏幕提示“please input PIN”,n=1[if !notATMCard][property n]
屏幕提示“please input PIN”,n=2[if !notATMCard] [property n]
屏幕提示“please input PIN”,n=3[if !notATMCard] [property n]
numkeyPad.getEntry(),
输入正确的PIN inputPIN=’123456’[if n=1]
输入错误的PIN inputPIN<>’123456’[if n=1]
输入正确的PIN inputPIN=’123456’[if n=2] and [if !validPIN&&n=1]
输入错误的PIN inputPIN<>’123456’[if n=2] and  [if !validPIN&&n=1]
输入正确的PIN inputPIN=’123456’[if n=3] and [if !validPIN&&n=2]
         输入错误的PIN inputPIN<>’123456’[if n=3] and [if !validPIN&&n=2]
bank.checkCard(),
为被盗ATM卡验证PIN ,isStolen=T[if !notATMCard]
为帐户关闭的ATM卡验证PIN,accountClosed=T [if !notATMCard]
为合法ATM卡错误输入PIN验证身份,accountClosed=F, 
isStolen=F ,validPIN=F[if !notATMCard&n<4]
为合法ATM卡正确输入PIN验证身份,accountClosed=F, 
isStolen=F ,validPIN=T[if !notATMCard&n<4]
bank.getFeeAmount(),
获取非成员卡用户交易服务费金额,定义feeAmount [if !notATMCard&&ValidPIN&&n<4 and !isMemberCard]
screen.prompt() 
屏幕提示“Fee Payed:XXX”  
numkeyPad.getEntry(), 
输入同意付费,declineFee=T
输入拒绝付费,declineFee=F    
screen.prompt()
屏幕提示“please select transaction”[if !notATMCard&ValidPIN&&n<4] and [if isMemberCard or !isMembercard&!declineFee]
这样我们符合spath[5]路径条件的相应的一个测试用例tcsuite[5]的最后结果为:
Test case 5:
外部事件:插卡
environmentcondtion: ATM卡,非成员卡,卡没有被盗,帐户没有关闭
input category:
inputPIN=’123456’ //输入有效PIN
declineFee=F  //输入同意付费
interaction behavior category:
session.beginSession(),     
为ATM卡合法持卡人建立会话
cardSlot.isATMCard(),
判断是ATM卡,读取卡号cardNum, notATMCard=F
screen.prompt(),
屏幕提示“please input PIN”,定义n=1
numkeyPad.getEntry(),
输入正确的PIN,inputPIN=’123456’
bank.checkCard(),
为合法ATM卡正确输入PIN验证身份,定义accountClosed=F, 
isStolen=F ,validPIN=T,ismemberCard=F;
bank.getFeeAmount(),
获取非成员卡用户交易服务费金额,定义feeAmount=xxx
screen.prompt() 
屏幕提示“fee Payed XXX”
numkeyPad.getEntry(), 
输入同意付费  定义declineFee=F
screen.prompt()
屏幕提示“Please select transaction”
预期的方法调用序列:session.beginSession(),cardSlot.isATMCard() ,screen.prompt() ,numKeypad.getEntry() ,bank.checkCard()  ,bank.getFeeAmount(),screen. prompt (),numKeypad.getEntry(),screen. prompt () 
后条件:
inputPIN=’123456’,!notATMCard, !isStolen, !accountClosed, validPIN&&n=1,
!declineFee
预期输出:
屏幕提示“please input PIN”
屏幕提示“fee Payed XXX”
屏幕提示“Please select transaction”
我们可以用同样方法为属于同一个用例的其他协作图构造了测试用例,则该用例的集成测试集构造完成。然后,可以用增量方式为组件、子系统、系统构造完整的集成测试用例集,而且可以用自动的方式进行。可以用[15]中的插装方法按照每一场景路径上的方法调用顺序,对待测试实现进行插装,这样在执行时可以观察到软件用相应测试用例运行的结果,并将观察到的实际执行结果与测试用例中的预期结果进行比较,如果一致,说明相应场景的实现与设计是一致的,否则,存在错误,并且错误在协作图的相应场景路径上,可以通过实际结果与预期结果发生不一致的地方定位错误,然后调试修改。
3.3算法实现工具框架
为了支撑上述测试用例生成方法的自动化,我们设计一个基于UML设计模型图的集成测试用例的自动生成工具UMLTGF,我们仍然使用UML为UMLTGF建模,本文给出UMLTGF的类图,如图3。相应的功能描述如下:
1、UML模型分析器。能够直接读取UML协作图规约的文本文件(如MDL文件)[11],进行解析,并获取对象角色、对象的属性和方法,链、约束,消息流和消息标签,存入相应的中间表,以便测试用例生成器使用;
2、协作集成测试用例生成器。根据消息的顺序号和条件,跟踪消息流,生成每条消息的直接后继,然后通过遍历消息及其直接后继的方法生成协作图上每个用例场景对应的协作的场景路径,同时可以获取场景执行的控制流和数据流,并用范畴-划分方法生成相应场景路径对应的集成测试用例。输入为从协作图中提取的信息中间表,输出为生成的测试用例集合;
3、测试用例管理。为使得生成的测试用例集可复用、可维护、无冗余,对每个测试用例设计了增加、修改、删除操作,用来在测试用例生成过程中管理这些测试用例集。

图3 UMLTGF类图
4、相关工作
尽管UML在工业界和研究领域用得相当广泛,关于UML生成测试的研究相对较少。一般测试生成都是将UML模型图转换到一个现成工具能够处理的中间的形式化描述,从而可以处理UML规约。基于UML分析、设计模型获取系统的相关信息生成各个阶段的测试用例的研究近年来有不少成果,从设计阶段的模型图生成集成测试用例的研究较少,[13]提出一个新的基于UML的测试模型生成集成测试的测试用例的方法,该方法首先分析软件系统的顺序图和协作图,提取组件间的事件流,根据组件之间的消息转移将顺序图和协作图划分为一组原子系统功能(ASF)单元,以每个ASF为一个节点、消息流为边构造测试模型,使用面向对象的集成测试方法在测试模型上生成测试用例。
[12]提出基于UML设计规约生成集成测试用例的方法,用UML状态机图建立软件动态行为的模型,组件之间的交互用图上注解表示,将设计规约模型转化为与集成系统的动态行为相应的全局FSM,在FSM上基于一定的覆盖准则使用常规的等价类划分方法生成可用于单元和集成测试的测试用例。[14]提出一种不需要其他形式化知识、只在UML框架内完成测试用例生成的UIT方法,选择实现和执行每个用例图描述的功能的相应顺序图、协作图以及类图,分析图中元素的语义,识别出作为测试单元的参与交互的对象和与其相关的消息的等价类,定义测试规约,从图中找到消息顺序,使用传统的Category Partition Method分析消息顺序,生成最终的测试用例。[15]分析了UML规约级和实例级协作图中所能表示的信息,将信息进行分类,有些信息可以用于对最终程序的静态检查,有些信息可用于动态测试;并设计了一个根据协作图中信息对相应生成的程序进行插装的算法,实现对测试满足测试准则的程度的度量,但生成测试用例的方法还没有给出。[16] 提出了一个基于UML顺序图设计的面向对象的软件的自动测试的概念和相应的实现工具SeDiTeC。该方法提出一个可测试的顺序图的规则,凡是满足可测试性需求的软件系统的顺序图设计模型都可以作为测试规约,并介绍了从一个顺序图中生成测试用例的方法,在SeDiTeC中实现了完整的测试过程
本文提出的从UML设计模型图(协作图、类图)生成集成测试用例的方法,可以对表示复杂场景的协作图进行处理,与上述方法是有一定区别,也是互补的。
5、总结和将来的工作
本文提出了一个基于UML协作图,采用协作集成测试模式生成集成测试用例的方法,用基于线程执行的方法识别协作图中的场景路径,用控制流和数据流方法遍历场景路径获取交互中的参数变量和方法调用序列,最后使用范畴-划分方法找到场景路径上的变量、方法、输入、输出、环境条件的合理组合作为覆盖该场景路径的测试用例;该方法的特点是:1、集合白盒方法和黑盒方法对协作图描述的灰盒行为进行测试;2、完全基于UML;3、生成较少的测试用例;4、便于实现自动化。
对基于UML生成测试用例的研究还存在许多不足。基于设计描述的形式化的测试准则相对还较少,基于UML模型图生成测试用例的方法也在不停的研究与发展中,目前对UML模型图作进一步精化或扩展其语义后,使用常规方法进行测试用例生成的情况较多,直接使用UML模型图提供的信息的方法较少;把单个模型图作为研究对象的较多,多个模型为同一测试用例生成提供信息的研究较少;针对测试过程中特定级别的测试(类级测试、集成测试)生成测试用例的方法较多,同一模型图为多个级别测试生成测试用例的研究较少;在具体的方法研究中,假设的前提和约束太多,还不能够达到实用的程度;对方法提供自动支持的工具大多是实验室原型,还不能应用到工业界;可应用的领域还有许多局限;缺少整体的、系统的解决方法,还没有能够把待测试系统的所有能够为测试用例生成提供信息的模型图综合利用,形成一个系统的测试用例生成方法,这也正是我们将来的研究方向。
我们将来的研究工作主要有几个目标:第一,提出一种与面向对象软件开发过程集成的测试过程,测试用例应以增量、系统的、与项目成本和进度相适应的可管理的数目的方法产生,利用业务模型生成用户验收测试的测试用例,利用UML分析模型生成系统测试的测试用例,利用UML设计模型生成集成测试的测试用例,利用实现模型生成单元测试的测试用例,能够合理计划测试资源,并能够对软件开发过程起到过程改进的作用;第二,针对UML单个模型图,研究其在为不同层次测试生成测试用例的方法,提出相应可行的测试准则和评估方法,尽量能够直接使用UML模型文档;第三,针对某一层次测试的测试用例生成时,研究综合利用待测试系统的各种模型图生成该测试层次的测试用例的方法;第四,为上述方法提供自动的工具支持,并希望能够与主流建模工具、测试工具集成。

参考文献:
[1]Imran Bashir, Amrit L. Goel, Testing Object-oriented Software: Life Cycle Solution[M],Springer-Verlag New York, Inc 1999
[2]David C.Kung, Pei Hsia, Jerry Gao, Testing Object-oriented Software[C], IEEE Computer Society,1999
[3] Beizer. Black-box Testing:Techniques for functional testing of software and systems[M], John Wiley&Sons,Inc, New York 1995
[4]Paul C. Jorgrnsen, Software Testing: A Craftsman’s Approach [M], CRC Press,Inc, 1995
[5]UML Specification 1.5[S], available at http://www.omg.org/uml
[6]Grade Booch, James Rumbaugh, Ivar Jacobson著 邵维忠等译  UML 用户指南[M], 机械工业出版社,Addison-Wesley 2001
[7]Grade Booch, James Rumbaugh, Ivar Jacobson著,姚淑珍,唐发根等译,UML 参考手册[M],机械工业出版社,Addison-Wesley 2001
[8]Grade Booch, James Rumbaugh, Ivar Jacobson著,周伯生,冯学民,樊东平 译,统一的软件开发过程[M], 机械工业出版社,Addison-Wesley 2001
[9]Robert V. Binder著 华庆一 王斌君 陈莉 译 面向对象系统的测试[M], 人民邮电出版社2001
[10]Philippe Kruchten, The Rational Unified Process –An Introduction[M], 2nd edition, Addison-Wesley, Reading, MA, 2000
[11]A. J. Offutt and A. Abdurazik, “Generating Tests from UML specifications,”[C] Proc. 2nd International Conference on the Unified Modeling Language (UML99), Fort Collins, CO, pp. 416-429, October, 1999. 
[12]Hartmann, J., Imoberdof, C., Meisenger, M., UML-Based Integration Testing, [C]in ISSTA 2000 conference proceeding, Portland, Oregon, 22-25 August 2000, pp. 60-70.
[13] Byoungju Choi, Hoijin Yoon, Jin-Ok Jeon, A UML-based Test Model for Component Integration Test,[C] Workshop on Software Architecture and Component, Japan, pp63-70, 1999.12
[14]Basanieri, F., Bertolino, A.: A Practical  Approach  to UML-based  Derivation  of Integration Tests.[C] Proceeding of QWE2000, Bruxelles, November 20-24, 3T.
[15]A. J. Offutt and A. Abdurazik, “Using UML Collaboration Diagrams for Static Checking and Test Generation,”[C] Proc. 3rd International Conference on the Unified Modeling Language (UML00), York, UK, pp. 383-395, October, 2000.
[16] Falk Fraikin, Thomas Leonhardt,Sequence diagram based test automation,[R]http://www.pi.informatik.tu-darmstadt.de/publikationen/technische%20Berichte/2002/pi2002-2.pdf
[17]Ye Wu, Mei-Hwa Chen and Jeff Offutt, UML-based Integration Testing for Component-based Software,[C] The 2nd International Conference on COTS-Based Software Systems (ICCBSS). pages 251-260, Ottawa, Canada, February 2003

原文转自:http://www.ltesting.net