这些协作图上的模型元素所表示的软件系统的不同方面的信息,都是系统的本质信息,需要在软件从设计到实现过程中必须保持的,因而软件实现中的行为的本质方面都会在设计中表示,所以可以从设计表示中获取行为方面的信息,用于确认软件实现中是否正确实现。
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],通过在协作中参与的组件来决定集成测试所有参与的对象。基于协作的集成测试需要检测协作的参与者之间的接口和交互,通过协作组织集成。每次处理一个协作,直到协作图上的所有协作都被测试。当所有构件的接口和构件之间的交互都测试完时集成测试完成。协作中包括的构件按照在一个处理线程、一个事件-响应路径来选择,要求系统中每个构件之间的消息已经被至少测试一次。我们前面定义场景路径正是一个线程完成协作执行的一个事件-响应路径,所以可能发生的错误会出现一条或多条场景路径上。