转自;http://www.ibm.com/developerworks/cn/rational/r-cn-rftmechanism/index.html
Rational Functional Tester 测试的前提
相信很多读者在接触 Rational Functional Tester 这类自动化测试工具后,都会有这样的疑问:它为什么可以操纵 Java 程序或者浏览器呢?
Rational Functional Tester 可以操控被测控件、完成用户指定的自动测试动作,但前提是它需要具备与被测应用程序(Application Under Test,AUT)进行通讯的能力。要做到这一点,Rational Functional Tester 首先必须建立自身与被测应用的沟通渠道,该过程对于 Rational Functional Tester 而言,被称为“启用被测应用程序”。
目前 Rational Functional Tester 可以支持如下领域的被测应用程序:基于 Java 平台的程序、基于 .Net 平台的程序、HTML 程序,以及基于 Siebel、SAP、Flex 等特定平台的应用程序。Rational Functional Tester 提供了这样的一个向导窗口来帮助用户“启用被测应用程序”,在这个简洁的对话框的“启用(Enable)”按钮和“测试(Test)”按钮的背后,还隐藏着更多的细节。
在 Rational Functional Tester 的术语词典里,这里的每一类应用程序都被称为“域”(domain)。建立沟通渠道的操作,都是作用在某个特定的“域”上,你可以在 Rational Functional Tester 和“Java 域”之间建立沟通渠道,这就是在 Rational Functional Tester 中启动 Java 被测应用程序的过程;依此类推,你也可以为 .Net 程序、 SAP 程序建立它们和 Rational Functional Tester 之间的特有的沟通渠道,使得 Rational Functional Tester 可以进而对 .Net 程序、 SAP 程序进行测试。在为每类程序(或进程)建好沟通渠道后,你还需要对渠道进行必要的测试,检验通讯是否能正常工作。Rational Functional Tester 正是通过这些沟通渠道来对被测程序(或进程)的控件发出指令、执行动作的。
建立沟通渠道时,Rational Functional Tester 对于被测应用程序,会新建一个 DomainImplementation 对象实例,由它来抽象出一个接口,提供具体的域相关细节给 Rational Functional Tester。DomainImplementation 对象的使命有:
- 获取该域最高级别的对象
- 注册该域可用的代理对象
- 为指定的控件创建代理对象
下图是启用浏览器环境的测试结果,可以看见 Java,HTML 两种 DomainImplementation 对象都被加载,来完成 HTML 被测应用的测试。(因为 HTML 应用程序在呈现时会涉及到 Java 内容)
“域”、“顶级对象”、“测试对象”、“代理对象”,又有这么多新名词出现,它们和 Rational Functional Tester 的运作有着怎样的关系呢?下面我们会逐一介绍它们的作用和典型动作。
Rational Functional Tester 进程级交互
Rational Functional Tester 进程模型
我们知道,运行中的程序和软件是以进程的形式存在的。首先我们来看一下 Rational Functional Tester 和被测程序间的进程相关细节。在 Rational Functional Tester 的设计规划里,各个相关进程按照所处位置和相对关系分成两类:客户端进程和服务器端进程。被测应用程序进程被称为“Rational Functional Tester 服务器端进程”,而录制,回放,对象查看器,和集成开发环境(IDE,Eclipse 或 Visual Studio .Net)等进程则被称为“Rational Functional Tester 客户端进程”。不论用户使用的是 Java 编程环境还是 .Net 编程环境来进行脚本开发,进程间的关系皆是如此,如下图所示。更直观地说,与 Rational Functional Tester 直接相关的进程是客户端,与被测程序直接相关的进程是服务器端。
Rational Functional Tester 与被测应用程序的进程级交互
Rational Functional Tester 客户端进程与被测应用程序进程进行交互,并从中获取必要的相关信息来完成录制、回放、对象查看之类的动作。它们借助进程间通讯(IPC)层的共享内存进行通讯。
Rational Functional Tester 给每个相关进程(包括客户端及服务器进程)创建测试上下文(TestContext)对象,并在共享内存里进行注册,该测试上下文对象是测试过程中用来操作被测程序的句柄(reference)。已注册的测试上下文对象将承担关联进程的所有通信。通常情况下,测试上下文对象会关联到一个操作系统级的被测进程,或测试客户端。当然,有时会有多个测试上下文对象关联到同一个进程。
两个被测应用程序的测试上下文(TestContext)对象是无法直接通讯的,它们需要一个中介:Rational Functional Tester 客户端进程的测试上下文对象,来传递通讯信息。图 5 的上半部是 Rational Functional Tester 客户端进程,下半部是各类服务器端进程,即被测程序,它们之间的交流和通讯只能在共享内存区域完成的。
注:侦窥内存,英文术语为 Spy Memory,即共享内存,其中的各类测试上下文承担被测程序及 Rational Functional Tester 间通讯功能。
Rational Functional Tester 进程通讯模型里的每一个进程都需要借由测试上下文(TestContext)对象来管理它的进程间通讯的调用和请求。Rational Functional Tester 客户端进程会和多个被测应用程序(AUT)进程交互,以 Rational Functional Tester 回放时的客户端 Find 进程为例,它会和所有的被测应用程序进行通讯来确定被寻找的控件对象。但在同一时间里,每个被测应用程序进程只能和唯一的 Rational Functional Tester 客户端进程交流。
对象管理器(ObjectManager)处理所有服务器端的进程通讯,以及与被测程序交互的元动作。对象管理器会有多个代理(Agent),每个对象管理器代理负责一类测试上下文对象的相关元动作。
在测试上下文(TestContext)对象里,域(TestDomain)对象是用于管理与它相关的特定通讯。例如,对于被测应用的浏览器进程,一个 HTML 测试上下文对象和一个 Java 域对象会被创建,因为浏览器里包含了隶属于 HTML 域的 HTML 元素,以及隶属于 Java 域的 Java Applets。
而在域(TestDomain)对象里,代理对象(ProxyObject)的作用是管理控件一级的通讯。它被 Rational Functional Tester 创建出来,用以和控件通讯,来操纵它们完成指定的功能测试动作。代理对象和被测应用程序的控件间有着一一对应的关系,任何控件间的交互都是通过代理对象这一媒介来达成。比如,各种不同类型的按钮分别会映射到不同的代理对象。
注:上下文对象,对象管理器,域对象和代理对象都是创建在被测应用程序进程里。
Rational Functional Tester 代理结构
Rational Functional Tester 与被测应用程序控件的交互,有两个必不可少的要素:代理对象(ProxyObject)和测试对象(TestObject)。代理对象包裹着实际的被测应用程序控件,测试对象则是该控件在脚本层面的展现,两者遥相呼应,传递测试的动作和信息。
注:为节约篇幅,这里仅以 Java 域的内容作介绍,.Net 域的情况也大致相似。
代理对象(Proxy objects)有些类似于实际图形界面控件的包裹类。Rational Functional Tester 与被测应用程序并不发生直接接触,任何与被测应用程序的通讯都需要对应的代理对象。代理对象创建后,被放置于被测控件能够访问并获取信息的地方。代理类可以用 Java 语言或者 C# 语言来开发,来实现规定的 Rational Functional Tester 与被测应用程序界面控件通讯的接口。
当您的应用程序实施了前文所提到“启用被测应用程序”操作后,它对应的代理类就会被加载到应用程序,成为被测应用程序的一部分。代理对象包裹着实际 GUI 测试对象(原生对象),使得它们可以被 Rational Functional Tester 识别和测试。以 HTML 程序为例,HTML 应用程序的浏览器被启用后,浏览器及其 HTML 控件的代理类都会被加载到浏览器中。对于 Windows Internet Explorer 浏览器,“启用被测应用程序”则会把 Internet Explorer 浏览器相关的代理类——浏览器辅助对象(Browser Helper Object)RTXIEEnabler.dll 文件作为第三方插件装入 Internet Explorer 浏览器插件集,RTXIEEnabler.dll 在启动后还将加载另外两个文件 rtxivsys.dll 和 rtxiedomain.dll,并与它们共同负责 Rational Functional Tester 和 HTML 被测程序间的交互行为。( 该过程和木马病毒的工作原理类似 )
另外,Rational Functional Tester 设计领先、开放灵活的架构允许用户可以创建新的 ProxyObject 类,或拓展某个现有的 ProxyObject 类来支持新的界面控件。
测试对象(TestObject)是被测对象控件的脚本端接口,界面控件在自动测试脚本里会表现为测试对象。例如,一个按钮控件被表述为 GuiTestObject,顶级容器对象如对话框或者框架控件被表述为 TopLevelTestObject。
测试对象(TestObject)方法的执行需要通过相应的代理对象(ProxyObject),测试对象驻留在 Rational Functional Tester 客户端,它拥有指向被测应用程序的代理对象的句柄。
Rational Functional Tester 对于每个支持的测试环境都已经提供了域对象,如 Java,HTML,.Net 等,并且在每个域里,还提供了所支持的各种被测应用程序控件的代理对象(ProxyObject)类。代理对象类与被测应用程序控件之间的映射关系被保存在 Rational Functional Tester 的安装路径下的可定制文件里,Rational Functional Tester 通过这些可定制信息来确定对于某种被测控件该使用哪种合适的代理对象。
注:被测控件和代理对象间的映射关系主要保存在文件 C:\Program Files\IBM\SDP\FunctionalTester\bin\rational_ft.rftcust 里。在相同路径下,还存有其他领域的,以及扩展的 rftcust 定制文件。
图 9 是打开后的 rational_ft.rftcust 文件,内容以 XML 格式展示,层次清晰,条理分明。大家可以看到代理管理器(ProxyManager)下辖五类测试域的代理对象,分别是 Java、HTML, .Net, Win 和 ActiveX。展开的 ActiveX 部分里还可以看见映射关系的细节:该领域的 DispHTMLObjectElement 控件对应着 Rational Functional Tester 提供的 Rational.Test.Ft.Domain.ActiveX.IEHtmlObjectElementProxy 类,自动测试脚本将通过这个类来操控 DispHTMLObjectElement 控件上的各种动作,完成既定测试。
图 9. rational_ft.rftcust 文件内容局部
每个 Rational Functional Tester 支持的实际控件都会对应着一个代理对象(ProxyObject),但有时也会有多个不同的控件对应同一代理对象的情况,如下图所示。出现这种情况的原因是,开发设计人员认为该代理对象提供的通用性接口已经足以覆盖这些控件的测试需求。当然,如果用户对某些控件有着更为细致的操控要求,可以自行拆解、拓展这一部分,使得 Rational Functional Tester 可以完成更细微的测试动作。
图 10. 一对一、一对多的映射关系(rational_ft.rftcust 文件内容局部)
即使是在默认配置下不为 Rational Functional Tester 所支持的新界面控件,用户也可以通过创建对应的代理对象类来拓展 Rational Functional Tester 的支持范围。例如,为了支持 .Net 域的 .Net 2.0 DataGridView 控件,用户可以开发一个代理类 Rational.Test.Ft.Domain.Net.DataGridViewProxy,并把它的声明插入到 rational_ft.rftcust 文件里对应的位置。下面的代码就是更新后的 rational_ft.rftcust 文件片段。
Rational Functional Tester 实际运行场景中的交互动作
介绍了相关的众多复杂概念后,接下来我们以最常见的录制、回放动作为例,剖析录制和回放的动作实质。
总体上看,录制和回放的过程会牵涉到对象管理器、域对象、代理对象、测试上下文之间形形色色的交互。
下面是录制测试步骤时,对象管理器和对象管理器代理间的动作:
- 定位屏幕上某处的对象。例如,proxyAtPoint 方法。
- 在对象图中获取识别属性,或者初始化对象句柄。例如,getMappedTestObject 方法。
而对于代理对象,录制时会调用到代理类里的以下方法:
动作 | 调用方法 |
进程级底层事件 | processMouseEvent() |
定位拖拽动作的目标对象 | getMethodSpecForPoint() |
验证点相关方法 | getTestDataTypes() getTestData() getProperties() getStandardProperties() getProperty() |
对象结构相关方法 | getMappableParent() getParent() getChildren() getMappableChildren() getOwner() getOwned() |
对象识别相关方法 | getRecognitionProperties() shouldBeMapped() getRole() getTestObjectClassName() getRecognitionPropertyWeight() |
某个录制动作的细节如下:
- Rational Functional Tester 录制器启动,从对象管理器中取得当前点的代理对象;(实际动作在之后的第二步、第三步完成)
- 获取所在域的顶级容器对象,返回;
- 在顶级容器对象的子对象里查找,得到当前点的代理对象,返回;
- 录制器得到当前操作的代理对象句柄;
- 处理鼠标事件;
- 设置事件或动作细节,返回并完成录制
Rational Functional Tester 使用的识别属性值和控件层次结构来识别被测控件,这些信息被集中储存在对象图(Object Map)里。回放时,这些信息被取出来用以选择唯一的界面控件。在必要的时候,Rational Functional Tester 也会搜集诸如屏幕坐标,控件属性等,连同界面控件一起,被表征为脚本端的测试对象(TestObject)。录制时,用户的各种点击、双击或拖拽动作都是被封装为独立的测试对象的方法,比如 button().click(atPoint(10,10)),回放时,Rational Functional Tester 用对象图里保存的识别属性找到对应的按钮型测试对象,再调用点击方法来施加测试动作。
回放时,Rational Functional Tester 客户端进程将请求发送到所有的测试域,在对象图里通过录制的可识别属性辨识出目标对象,不同的识别结果会引发 Rational Functional Tester 不同的后续动作。
结果 | 动作 |
未发现目标对象 | 抛出对象未发现的程序异常 |
发现多个目标对象 | 将对象查找分值和阈值比对,来确定唯一的目标对象;如果不能确定,将抛出对象不确定的程序异常。 |
发现唯一的目标对象 | 代理将启动回放动作。例如,回放之前录制下来的、诸如点击的动作。 |
在识别阈值内,发现多个目标对象 | 抛出对象不确定的程序异常。 |
图 13 是一个点击动作的回放,细节如下:
- Rational Functional Tester 脚本开始回放;
- 通过对象管理器获得该域顶级容器对象;
- 遍历顶级容器对象的子对象,直至得到满足查找条件的对象的代理;
- 通过该代理触发点击动作;
- 激活目标对象,计算它的所在位置,并在居中的坐标实施点击;
- 结束;
Rational Functional Tester 的功能测试或回归测试正是由更多、更复杂的录制 / 回放动作组合而成,原理与上述两个例子没有太大差别。
以上就是我们对 Rational Functional Tester 工作原理的剖析,大家可以从中了解到它掌控被测软件,并驱动它们完成自动化测试的底层动作细节。知其然,并知其所以然。在这一基础上,大家还可以进行定制,自行拓展 Rational Functional Tester 的测试范围和深度,使它的能力更加吻合应用项目的需求,保障软件质量。
最后我们来回顾一下本文的要点内容,帮助您更好的掌握和理解:
- Rational Functional Tester 在测试前需要启用被测应用程序,在两者间建立沟通渠道;
- Rational Functional Tester 测试涉及的进程被分为两类,被测程序是服务器端进程,Rational Functional Tester 这一侧是客户端进程;它们的通讯借助共享内存完成,涉及上下文对象,对象管理器,域对象和代理对象等一系列实体;
- Rational Functional Tester 不直接和被测应用程序接触,而是通过代理对象这一包裹类来操作实际控件;
- 代理对象和测试对象的映射关系及其存储结构,用户可以拓展映射关系来扩大测试范围;
- 实际录制、回放过程的详细交互动作,所调用的底层方法及其时间顺序。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/14780873/viewspace-628571/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/14780873/viewspace-628571/