本文来自于 Rational Edge:作者在这篇文章中介绍了一项软件测试技术,它可以在决策过程中帮助用户使用自动化测试工具,而不再需要经常使用的硬编码。
使用传统的制表格式介绍决策过程。 1 决策表提供了一个简单的,可视化的帮助,它可以在知识库系统中被使用,来高效的执行验证过程。在软件开发过程中,决策表能够帮助测试小组在软件应用程序中管理复杂的逻辑性。
这篇文章介绍了一种基于决策表的测试技术,描述了一种使用 IBM Rational Functional Tester 和 IBM
Rational Software Modeler 的实现方法。这项技术常常通过运行一系列复用测试脚本来详细描述非回归测试套件。每一个测试脚本都是使用
Functional Tester 的 GUI 记录/回放技术产生的。
这里,我的目标是"概念证明"。为此,我花费了5天的时间开发了一个Java类库,用来使用 IBM Rational
工具实现决策表技术。虽然这项技术还没有被部署到实际项目中,但是我会通过使用基于Eclipse框架的IBM Rational工具来论证这个方法的潜力。我计划的实现方法是完全基于标准的,文档化的接口,任何读者都可以很容易的理解。
问题
非回归测试是基于数据驱动的测试技术,一个简单的测试脚本会根据输入数据的不同而反复的被使用,这在测试自动化方面是很常见的。 3
这项技术可以使用Functional Tester中的数据池来实现,这些数据池是在一个测试脚本建立期间或者建立之后关联在测试脚本上的。不幸的是,当测试应用程序陷入复杂的逻辑中时,数据驱动的测试在没有硬编码的情况下变得难以实现。一般来说,应用程序的行为是受组成测试套件的测试脚本的不同输入数据影响的。我们需要使用等值划分来区别输入的数据,它可以提供一个AUT(被测试的应用程序)的等价行为。在每一个测试套件中都要使用硬编码环境,它能帮助我们向着正确的测试路径前进,并且可以处理数据的变化。这个方法不仅适用于测试人员,同样对于开发人员来说也很"有趣",特别是在使用自动化测试工具时,因为在硬编码的测试脚本环境中,使得维护以及测试脚本的扩变得非常难以管理。此外,如果在头脑中没有一个清晰的策略,是很难优化测试脚本分解的。
建议方法
当一个测试人员手动实现一个测试程序时,他会根据测试目的选择输入的数据,并根据AUT的行为作决策。问题是,我们怎样在不使用硬编码而使用自动化测试工具的决策制定过程中帮助测试人员?
这个简单的问题使我们去考虑决策表技术,并开发一个Java类库来验证这个概念。决策表通过Functional Tester数据池实现。通过决策表提供的用于解释测试逻辑的决策脚本,被整合到测试套件的体系架构中,如图1所示。其他组成测试套件的可重用测试脚本是通过使用Functional
Tester的GUI记录/回放技术产生的。一个测试片断被定义成一个测试脚本的序列,它可能是两个决策脚本之间的序列,或者是开始脚本和决策脚本的序列,再或者是决策脚本和结束脚本的序列。一个数据驱动表和测试套件连接在一起,它可以根据不同的输入数据重复运行测试套件,并把结果输入给不同的测试脚本。
图1:由测试脚本和决策脚本组成的测试套件。
这项技术提供了以下好处:
- 一种详细描述测试套件和测试脚本的形式化方法
- 在决策脚本中封装测试套件逻辑
- 以决策点为中心的测试套件体系架构
- 测试逻辑可以很容易地使用决策表进行追踪与变更,这样可以被非程序员阅读和填写
- 一个更加灵活的数据驱动的实现方法。
基于决策表的测试技术
在测试过程中当达到一个决策点时,测试人员会检查AUT的状态并决定测试活动。每一个决策点都可以用一个决策表来指定。一个决策表由两部分组成:条件和活动。决策表列出了一个测试活动执行所需的条件。每一个条件表达了各种变量之间的关系是正确的还是错误的。所有可能的条件组合定义了一系列的选择。对于每一个选择,测试活动都要考虑到。选择的数量使得条件种类呈指数级增加,可能会显示为2NumberOfConditions。当决策表变得复杂时,一个新的决策表层级就会被创建。
由于一些选择的情况是不存在的,所以一个测试策略应该是:1) 验证所有可能实现的选择。2) 描述AUT是如何在所有选择环境下运转的。有了决策表,我们就可以根据测试策略轻松的添加和删除条件。我们可以根据测试策率的需要,通过反复的添加新的测试条件来增加测试的覆盖率。
如图2所示,决策表在指定,分析和测试复杂逻辑性时起到很重要的作用。它们可以很有效的描述不同条件产生不同的测试活动。它们还可以有效的查找到执行与规范中的错误。
图2:一个决策表的例子
回页首
使用决策和数据驱动表
在每一个决策点,一个决策表要列出AUT(根据条件)需要校验哪些内容,以及下一个活动是什么。由于决策表中已经定义了逻辑,所以测试人员不需要硬编码任何测试逻辑。决策脚本只需在运行期间执行确认工作,比较决策表提供的验证结果,并且如果找到了解决方案,返回并运行下一个测试脚本。
一个测试套件脚本包含很多决策脚本和测试脚本。一个测试套件的所有元素都在一个驱动表中被定义,在这个驱动表中列出了一系列无序的测试片断。每一个测试片断由在两个决策脚本之间顺序执行的测试脚本组成。对于每一个测试片断来说,驱动表列出了一个源测试脚本和一个目标测试脚本之间的转换。
随着决策在执行期间被决策脚本动态的计算出来,需要为测试套件脚本实现一种通知机制,用来通过测试脚本通知下一个需要运行的测试脚本。当决策脚本通知测试套件脚本下一个应该运行的测试脚本时,测试套件脚本请求驱动表,查询下一个应该运行的测试片断。这个过程如图3所示:
图3:一个测试套件的元素
一般情况下,一个测试套件中的任何测试脚本都需要为数据输入连接到一个数据池。当一个数据驱动表连接到测试套件时,我们就可以将输入的各种组合的数据记录列入到测试脚本和动态变化的AUT行为中。当AUT的行为发生变化时,每一个决策脚本提供的结果都会变化,因此通过AUT的测试路径就会变化。通过一个简单的测试套件脚本,我们可以验证很多测试路径。这样可以轻松的合并输入的数据和扩大测试套件的范围,并在决策表中添加新条件。
这种方法清晰的将决策脚本中的测试逻辑封装与测试脚本中执行的测试动作和验证分离开来。AUT中决策点的识别,能够帮助我们形式化并且精化从测试套件到测试脚本的分解。
回页首
使用 Functional Tester 实现此项技术
作为这个概念证明的一部分,我开发了一个Java库,用来使用Functional Tester实现基于决策表的技术。请按照下列步骤建立一个测试套件脚本:
- 重用测试套件代码模版并填写测试套件驱动表
- 使用一个代码模版建立决策脚本,并填写决策表
- 填写数据驱动表
基于决策表的测试库
基于决策表的测试库由Java类组成,它提供了下列服务:
- 初始化并重复的穿过在驱动表中定义的测试套件结构
- 浏览决策表并比较AUT中执行的验证选择
决策脚本和测试套件脚本之间的事件侦听机制对于测试人员来说是透明的。它是通过库中的DecisionBuilder和TestSuiteDriver类来实现的,如图4所示。为了使用库中的服务,测试人员建立的每一个测试套件脚本以及决策脚本都必须继承TestSuiteHelper
4 类,因为它提供了一个连接到库的接口。为此,测试人员每次建立新测试套件或者决策脚本时都需要选择这个父帮助类。
图4:基于决策表测试库的主类
建立一个新的测试测试套件
测试套件可以在业务层面或者系统用例层面被用来实现自动化测试策略。在系统用例层面,一个测试套件实现用例场景。在页面层面,一个测试套件跨越几个用例追踪业务流程。对于一个给定的测试级别,测试套件可以根据回归测试计划中定义的测试目标来组织。例如,测试套件可以集中在业务规则验证或者服务传递或者数据完整性检查(创建,更改,删除)上。虽然理论上可以只使用一个测试套件,但是在实践中这种情况难以管理。因此,测试人员必须根据测试选择设计测试套件,并且拥有一个运行测试套件的测试套件是有意义的。
为了建立一个新的测试套件,测试人员需要做以下工作:
- 使用Functional Tester建立一个空的测试脚本
- 在测试套件脚本中插入代码模版(测试套件的代码模版如图5所示。)
- 列出驱动表和数据驱动表的名
图5:测试套件脚本的代码模版
如图6所示,每一个测试套件的结构都在测试套件驱动表中描述了,一个数据池定义了测试脚本(例如从源脚本到目标脚本的转换)。次序并不重要,因为TestSuiteDriver类可以解析驱动数据池并且在存储器中加载测试套间的结构。然而,你必须定义开始和结束脚本。测试人员可以填写这个表格,来指定测试套件或者从测试套件的UML定义产生这个数据池(可以在稍后的章节查看"使用IBM
Rational Software Modeler模块化设计测试套件")。
图6:测试套件驱动表的实例
建立一个数据驱动测试套件
一个数据驱动表可以被连接到测试套件脚本,用来1) 控制数据输入到不同测试脚本以及2) 建立通过AUT的不同路径。数据驱动表的标题包含测试套件的测试脚本所使用的数据池的名称。数据驱动表的每一行表示一种不同的输入数据记录的整合,这个输入数据记录用在每一个测试脚本数据池中。如图7所示,数据驱动表的第一列是一个测试套件的true/false标志位,这个标志位用来表示一行是否依靠于测试对象。
图7:测试套件数据驱动表的实例
每一个测试脚本数据池通常包含一个标志,它用来显示测试脚本在数据池的完整回归过程中是否必须选择一项记录。当测试套件开始新的回归时,TestSuiteDriver类会读取测试套件驱动表,并设置测试脚本数据池选择标志位,所有测试脚本都会重复这项工作。因而,当一个测试脚本数据池记录发生回归时,只有驱动表中列出的记录会被考虑。这个机制被库文件管理,并且对于测试人员来说是完全透明的。唯一的约束就是所有数据池的SelectRecord标志位。
建立一个决策测试脚本
测试人员识别测试套件流中的决策点,并为每一个决策点建立一个决策测试脚本。当测试套件流通过UML实体图设计时,每一种条件(请查看"使用IBM
Rational Software Modeler 建模测试套件"章节)都会建立一个决策测试脚本。
为了执行一个决策点,测试人员需要完成以下工作:
- 建立并填写决策数据池
- 建立一个空决策测试脚本并插入代码模版
- 为每一个决策条件注册验证点
首先,测试人员使用Functional Tester数据池建立一个决策表。决策表的实例如图8所示,它也可以通过测试套件的UML定义产生请查看"使用IBM
Rational Software Modeler 建模测试套件"章节)。决策脚本把AUT执行的验证结果与条件入口相比较,以便识别执行的测试活动(例如下一个需要运行的测试脚本)。当一个合并不可能或者还没有被实现时,数据池中的行将会被排斥,并且测试活动是未定义的。
图8:测试表的实例
第二步,测试人员建立一个空的测试脚本,在测试脚本中插入代码模版(如图9所示),并列出决策数据池的名称。测试人员使用Functional
Tester插入确认点来捕获决策表所需信息。
图9:决策脚本的代码模版
回页首
使用IBM Rational Software Modeler 建模测试套件
测试套件使用一个UML活动图来设计,图中每一个活动都和一个测试活动(测试脚本)通信,并且每一个决策都会和一个决策脚本通信,如图10所示。决策点列出的条件用来产生通讯的决策表。活动图很容易被非开发人员使用和理解。
图10:UML规范产生的测试套件执行。
一个"datastore"类型的目标节点可以被连接到一个测试活动,来指定这个测试活动需要的一个数据池。通过类指定数据池结构也是可行的方案。数据池的每一列都会和一个类的属性通信。一个UML解析器可以产生所有Functional
Tester运行测试套件所需的数据池,包括驱动表,决策表和数据驱动表和测试脚本数据池的结构。活动图表和类图都可以在一个协作元素下组织起来,如图11所示。可追溯的连接可以在测试套件定义和用例模块之间建立,如图12所示。一个更加成熟的方法可以使用IBM
Rational Software Modeler提供的转换工具进行开发。
图11:测试套件的定义被封装在一个协作之下。
图12:测试套件和其他模块元素之间的追踪连接
我开发了一个UML解析器,它能够以XML格式产生测试套件驱动表,决策表以及数据池(例如数据驱动表和测试脚本输入数据表的结构)。当选择协作时,一个拥有上下文菜单的Eclipse插件程序将会被用来产生测试套件表,如图13所示。
图13:类库用来从UML定义产生测试套件表
所有可能的选择都自动的产生在决策表数据池中,如图14所示。只产生了活动图中列出的测试活动。新的测试活动没有被列在活动图表中,但是可以在导入到Functional
Tester测试项目之前添加到决策表中。
图14:决策表中产生的所有可能组合。
回页首
结论
我相信这种基于决策表的测试技术能够极大得改进测试人员在自动化测试期间管理决策的能力。使用IBM Rational Functional
Tester和IBM Rational Software Modeler,这项技术可以通过实现一个可复用的测试脚本来促进非回归测试套件。
正如我在介绍中提到的,虽然这项技术还没有应用到实际项目中,但是使用出于此目的而建立的Java类库显示这项技术是可行的。
进一步的工作现在正在进展中,它可以扩展测试建模方法的引入。IBM Rational Software Architect提供的模型转换服务将会用于测试自动化的辅助设计。
我们欢迎你在阅读完这篇文章后给我们提供反馈。有问题请联系:vauthier@fr.ibm.com |