宋 政君, 软件测试工程师, IBM 余 晓峰, 软件测试工程师, IBM
2008 年 5 月 06 日 IBM Rational Functional Tester(RFT)是由 IBM 推出的针对 Java、.Net 和 Web 应用程序的自动化测试工具。借助这一工具,测试人员可以轻松地录制或编写脚本来进行自动化测试,极大地提高了测试效率。但是 RFT 目前不能捕捉到 SWT(Standard Widget Toolkit) 应用程序的对象,不能录制 SWT 应用程序的任何动作。本文介绍了一种解决方法,能够使 RFT 捕捉到 SWT 应用程序的对象,并且采用 AOP(Aspect Oriented Programming)后编译时(Post-Complier weave)的方式把它注入到 SWT 应用程序中。该方法无须更改 SWT 应用程序的源代码,减少了开发代码与测试代码的耦合,在基于 SWT 应用程序的测试中有广泛的应用前景。
1. RFT 及 SWT 简介
本文主要介绍如何用 Rational Functional Tester(RFT)工具测试 SWT 应用程序,因此本节首先简要介绍一下 RFT 和 SWT。
RFT 介绍
RFT(IBM® Rational® Functional Tester)是 IBM 公司研发的一个面向对象的自动测试工具,提供了自动化测试 Java 程序、Web 应用、Eclipse 以及终端应用的解决方案。您可以通过捕捉对象,记录用户操作的过程的方法,动态的生成测试脚本,然后在不断的回放测试脚本自动测试应用程序,提高测试效率。图 1 所示的就是 RFT 对象映射编辑器,从图中可以看出,这些被录制工具加进来的对象组成了树形的结构,每一个对象都有相关的识别属性。例如图中高亮显示的 Button 对象,它的 .class 属性值为 javax.swing.JButton,说明这个对象是 Swing 库的按钮组件。它还有其他属性,每个属性的值后面都跟有权重值,权重值对测试程序运行过程中对象识别非常重要。
图 1. 对象映射编辑器
SWT 介绍
SWT(Standard Widget Toolkit)标准窗口小部件工具箱,编程人员可以使用它来开发适用于 Eclipse 环境的图形用户界面(GUI)以及开发单独的 GUI 本机应用程序。SWT是 一个库,它创建了 Java 版的本地主机操作系统 GUI 控件,依赖于本机实现。这意味着基于 SWT 的应用程序具有以下几个关键特性:
-
所提供的窗口小部件(widget)反映了主机操作系统上提供的窗口小部件(组件和控件)。
-
主机 GUI 库的任何特殊行为都在 SWT GUI 中得到反映。
本文介绍一个 SWT 应用程序,代码如清单 1 所示,本文读者应该熟悉 SWT 的知识,因此对代码不做解释,完整代码可以从本文 下载部分 下载。
清单 1.
public class Calculator extends Composite {
public Calculator(Composite parent, int style) {
super(parent, style);
}
private CalculatorModel model = new CalculatorModel();
private Text lcd = new Text(this, SWT.BORDER | SWT.RIGHT);
省略……
public static void main(String[] args) {
Display display = Display.getDefault();
Shell shell = new Shell(display);
shell.setText("Calculator");
shell.setLayout(new FillLayout());
Calculator cal = new Calculator(shell, SWT.NONE);
cal.init();
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
|
编译并导出为 calculator.jar 文件,运行 calculator.jar 结果如图 2 所示,这是一个计算器的 SWT 应用程序。
图 2. 计算器
2. 使用 RFT 测试 SWT 应用的问题
RFT 主要通过捕捉应用程序对象,刻录用户操作应用程序的过程,然后通过回放来完成测试任务,但 RFT(本文以 IBM® Rational® Functional Tester 版本 7.0 为例)目前却捕捉不到完全使用 SWT 库开发的应用程序的对象。如上节清单 1 所示的 SWT 应用,利用 RFT 的对象捕捉功能就无法捕获到任何 SWT 对象,图 3 是 RFT 的对象捕捉器,左键按住手形的对象选择器不放,将鼠标移到 SWT 应用程序上,如果有对象被红框包围,说明 RFT 可以捕捉到对象,但图 4 中任何对象都没有被红框包围,说明 RFT 没有认出此对象。
图 3. RFT对象捕捉器
图 4. SWT 计算器
问题分析
上例中 RFT 不能捕捉 SWT 应用程序对象的原因有:
-
本文中使用的 SWT 应用程序是完全使用 SWT API 开发的应用程序。
-
RFT 对于测试这种 SWT 应用程序是有限制的,目前 RFT 7.0.1 版本及以前的低版本的 RFT 都没有提供相应的解决方法。
更多请看 Tech note。
3. 解决方案:直接修改 SWT 应用程序源代码
为了使 RFT 能够捕捉到 SWT 程序的对象,您必须将清单 2 的代码添加到 SWT 应用程序的源代码中:
清单 2.
try {
com.rational.test.ft.bootstrap.Bootstrap.enableSwtUi(display);
}
catch (Throwable e){
}
|
其中:Bootstrap 类是 RFT 的运行时环境中 rational_ft_bootstrap.jar 文件包中的类。以上节的 SWT 程序为例,修改后的代码如下:
清单 3.
public class Calculator extends Composite {
public Calculator(Composite parent, int style) {
super(parent, style);
}
private CalculatorModel model = new CalculatorModel();
private Text lcd = new Text(this, SWT.BORDER | SWT.RIGHT);
//省略……
public static void main(String[] args) {
Display display = Display.getDefault();
Shell shell = new Shell(display);
try
{
Bootstrap.enableSwtUi(display);
}
catch(Throwable throwable) { }
shell.setText("Calculator");
shell.setLayout(new FillLayout());
Calculator cal = new Calculator(shell, SWT.NONE);
cal.init();
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
|
并且为了能够编译和运行,您还必须把 rational_ft_bootstrap.jar 添加到 class path中,确保 SWT 应用程序运行时能够找到 Bootstrap 类。重新编译运行上面的例子,然后打开 RFT 的对象捕捉器,左键按住手形的对象选择器不放,将鼠标移到 SWT 应用程序的按钮对象上,如图 5 所示,SWT 对象被红框包围,并在下方显示出该对象的类型是:org.eclipse.swt.widgets.Button,说明 RFT 可以成功捕捉到 SWT 的对象了。
图 5. 捕捉 SWT 对象
方案分析
上述的解决方案很好的解决了 RFT 捕捉 SWT 应用程序对象的问题,而且添加代码后,原有 SWT 应用程序的功能完全不会受到影响。但是却引入了新的问题,它使得 SWT 的应用程序编译和运行必须依赖 rational_ft_bootstrap.jar 文件,而这个 jar 文件是 RFT 工具中的一个的文件,并且引入这个 jar 文件仅仅是为了测试目的。
企业应用程序开发会涉及具有单独的小组,拥有清楚的职责的大型项目团队。团队常常被分成更小的分析人员团队、开发人员团队和测试人员团队。每个团队由清楚的任务划分,开发团队开发应用程序的时候不会考虑测试的问题,导致他们不会把上述解决方法的代码写到程序中,而测试团队也不能仅仅为了提高自动测试的效率,让开发团队修改代码,依赖 RFT 的 rational_ft_bootstrap.jar 文件,并且在最终的产品中也必须要包含这个文件。
4. 改进的方案:AOP 编译后方式修改 SWT 应用程序
难道就没有好的办法解决吗?当然有,本文采用了 AOP 后编译 Weave (织入)代码的方式,很好的解决了这个新问题。
AOP 和 AspectJ 简介
对于 AOP (Aspect Oriented Programming),即面向方面编程而言,程序的主要逻辑部分和 Aspect 功能部分的具体实现都可以采用传统的面向对象技术等实现,这里没有什么新东西。AOP 最为特别并使其相对其它方法具有明显优点的部分就在于它能够以多样的方式将程序中用到的多个方面灵活的 Weave 到一起,形成一个完整的应用程序。如何以准确、简洁、灵活的方式将各个不同的方面 Weave 到一起,就成为了我们最需要注意的关键点。大致上,Weave 操作可以发生在如下几个阶段:
-
编译时:在对源代码进行编译时,特殊的编译器允许我们通过某种方式指定程序中各个方面进行 Weave 的规则,并根据这些规则生成编译完成的应用程序。
-
编译后:根据 Weave 规则对已经完成编译的程序模块进行 Weave 操作。
-
载入时:在载入程序模块的时候进行 Weave 操作
-
运行时:在程序运行时,根据程序运行时的情况 Weave 程序中的对象和方面
AspectJ 是 AOP 最成熟的 Java 语言的实现,获得了 Java 程序员的广泛关注,它提供了一整套的语法,能够清楚的描述横切关注点,并将其 Weave 到 Java 源代码中。Weave 后的代码仍是标准 Java 代码,AspectJ 编译器生成的是符合 Java 字节码规范的 .class 文件,这使得所有符合规范的 Java 虚拟机都可以解释,执行其所生成的代码。
本文采用 AspectJ 1.5.3 版本,可以从 aspectj 网站下载(参见 参考资料)。
-
AspectJ 1.5.3 的安装,在安装之前,确保您的电脑已经安装了 JDK(推荐安装 JDK5.0),打开命令行窗口,运行:
<java_home>/bin/java
–jar <aspect_installable_dir>/aspectJ1.5.3.jar
|
-
配置环境变量
classpath,将
<aspectj
_
install
ed_
dir>/lib/aspectjrt.jar 添加到系统的 classpath 中。
-
配置环境变量
path,将
<aspectj
_
install
ed_
dir>/bin 添加到系统的 path 中。
注:
-
<java_home>
指的是 JDK 的安装目录
-
<aspect_installable_dir>
指的是 aspect1.5.3.jar 文件所在的目录
-
<aspect_installed_dir>
指的是 Aspect 1.5.3 的安装目录
AOP 方式修改 SWT 的实现
为了解决模块化编程的要求,有些 AOP 框架开始支持后编译时 Weave 的功能。程序员只需要获得编译完成之后的模块,就能进行 Weave 操作。AOP 的灵活性,把一大堆紧密耦合的代码转变成一个强大的、可扩展的企业应用。利用 AOP 的后编译特性,成功地解决了本文遇到的难题
,本文的例子采用 AOP 编译后 Weave 的方法将 清单 2 的代码写入到 SWT 的字节码文件中,具体分以下几步:
步骤 1.
首先我们必须得到 SWT 应用程序编译后的字节码文件包,本例的计算器程序字节码文件 calculator.jar。
步骤 2.
采用 AspectJ 语言来实现 AOP,在 SWT 应用程序中 weave 一段代码。下面让我们了解一下本例采用 AOP 编程中的一些实际概念:
-
方面(aspect)类似于 Java 编程语言中的类。方面定义切入点和通知(advice),并由诸如 AspectJ 这样的方面编译器来编译,以便将横切织入现有的对象中。
-
一个 连接点(join point)是程序执行中一个精确执行点,比如类中的一个方法。例如,对象
Calcuator 中的 new Shell(display) 方法就可以是一个连接点。连接点是个抽象的概念;不用主动定义一个连接点。
-
一个切入点(pointcut)本质上一个用于捕捉连接点的结构。例如,可以定义一个切入点来捕捉对象
Calcuator 中的 new Shell(display) 的所有调用。和连接点相反,切入点需要在方面中定义。
-
通知(advice)是切入点的可执行代码。本例中切入点捕捉对象
Calcuator 中的 new Shell(display) 的调用,然后该通知动态地插入 清单
2 代码。
AspectJ 实现 AOP 的源代码如下:
清单4 .
package sample;
import org.eclipse.swt.widgets.Display;
public aspect EnableSWT {
/** pointcut */
pointcut enableSwtUi(Display display):
call(org.eclipse.swt.widgets.Shell.new(Display, ..))&& args(display, ..);
/** advice */
after(Display display) returning: enableSwtUi(display) {
System.out.println("enableSwtUi()");
try {
com.rational.test.ft.bootstrap.Bootstrap.enableSwtUi(display);
} catch (Throwable e) {
}
}
}
|
保存文件为 EnableSWT.aj,然后编译并导出为 aspect_swt.jar 字节码文件。
步骤 3.
通过 ajc 命令将代码 weave 到 SWT 的字节码中,并生成一个新的字节码文件包calculator_aop.jar。
打开一个 command 窗口,输入下面命令:
ajc -classpath ".;calculator.jar;aspect_swt.jar;%classpath%"
-inpath calculator.jar -aspectpath aspect_swt.jar -outjar calculator_aop.jar
|
注:
-
-classpath
指的是编译过程用到的 jar 文件
-
-inpath
指的是要被修改的 SWT 应用程序二进制文件
-
-aspectpath
指的是从哪个方面 weave 代码
-
-outjar
指的是 weave 后产生的 SWT 应用程序的新 jar 文件
反编译新产生的 calculator_aop.jar 文件中 Calculator.class 文件,weave 后的部分代码如清单 5。
清单 5 .
……
public static void main(String args[])
{
Display display = Display.getDefault();
Display display1 = display;
EnableSWT.aspectOf().ajc$afterReturning$sample_EnableSWT$1$2f852f6e(display1);
Shell shell = new Shell(display1);
shell.setText("Calculator");
shell.setLayout(new FillLayout());
Calculator cal = new Calculator(shell, 0);
cal.init();
shell.pack();
shell.open();
while(!shell.isDisposed())
{
if(!display.readAndDispatch())
{
display.sleep();
}
}
display.dispose();
}
……
|
可以看到代码 EnableSWT.aspectOf().ajc$afterReturning$sample_EnableSWT$1$2f852f6e(display1);通过 AOP 的后编译方式插入到 SWT 应用中,这段代码运行的结果等同于 清单 2 的代码。
运行 SWT 应用程序和 RFT 捕捉对象
通过新生成的 calculator_aop.jar 文件运行 SWT 程序,打开 RFT 捕捉器捕捉 SWT 整个应用程序,效果如图 6 所示,整个 SWT 应用被红框所包围,并在下方显示出此对象的类型是:org.eclipse.swt.widgets.Shell,说明 RFT 已经捕捉到 SWT 对象。
图 6. 捕捉 SWT 对象
5. 总结
本文介绍了一种方法实现了 RFT 对 SWT 应用程序对象的捕捉,并采用了 AOP 编译后 Weave 方式将解决方案的代码植入到 SWT 应用程序的字节码文件中,解决了开发程序代码和测试程序代码的紧耦合问题,提高了测试效率。
免责声明
本文仅代表本人观点,并非代表 IBM 的立场、策略和观点。
下载 | 描述 | 名字 | 大小 | 下载方法 |
|---|
| SWT 应用程序源码 | swt-src.zip | 3 K | HTTP |
|---|
| AspectJ 代码 | aspect-src.zip | 1 K | HTTP |
|---|
参考资料 学习
获得产品和技术
讨论
作者简介  | |  | 宋政君 IBM 上海研发中心从事软件开发和测试的工作,目前正在测试 Lotus Connections 产品,这个解决方案已经成功地用到LotusConnections测试中。对 Rational Functional Tester 的使用和开发有浓厚兴趣,并且对 WebSphere Application Server/Portal 有深入的研究。 |
 | |  | 余晓峰 IBM 上海研发中心从事软件开发工作,关注于数据库管理以及 SQL 及数据库的性能调整。 |
对本文的评价
|