如今 Eclipse
RCP 平台已成为 Java 平台上的富客户端首选,而 SWT 和 JFace 的高效率也让诸多 Java 界面开发者受益匪浅。在插件化已经成为一种潮流的今天,我们迫切需要一种自动化的界面测试工具去测试
Eclipse 的插件。Abbot 框架就是这样一种自动化的UI测试工具,它提供了一系列的能够执行 Swing 或者 SWT 界面测试的
API,并提供了脚本录制和编辑、运行的工具。Abbot 的 SWT 版本是基于 Eclipse 的插件形式发布的,天然的支持了 Eclipse
插件的自动化测试。 本文详细的描述了 Abbot SWT 插件的配置和使用,分析了
Abbot 的体系结构和工作原理,并给出复杂的测试用例来说明 Abbot SWT 的一些高级用法,同时还分享了作者的一些 Abbot
相关的最佳实践,相信会对从事 Eclipse 插件和 SWT 用户界面的开发和测试人员有一定的帮助。
引言
从 JDK 1.3 以来新增加的一个特性就是对图形用户界面自动化测试的支持,通过使用 Java.awt.Robot
类和相关的功能,程序员可以调用 JDK 的 API 可以直接实现用户界面的操作,常被用作用户界面的自动化测试,但是这些底层的 API
使用起来不是很方便,所以 JFCUnit 和 Jemmy 等测试工具都对 Java.awt.Robot 进行了包装,能够在 API
级别直接支持 AWT 和 Swing 的用户界面测试。但是到目前为止,它们尚不支持 SWT。SWT 作为 Eclipse 插件界面开发的首选,正日趋完善和流行,因此大量的程序员在开发
Eclipse 插件和 SWT 的用户界面时,往往需要千百次的点击鼠标去重复的测试图形用户界面,繁琐而且效率低下。
幸运的是,我们有 Abbot,一个可以自动化的测试 SWT 和 Eclipse 插件用户界面的测试框架。Abbot
是 sourceforge.net 站点上的一个优秀 Java GUI 测试框架,最初主要支持 AWT 和 Swing 的用户界面自动化测试,后来随着
SWT 的流行,就增加了对 SWT 的支持。为了与 Eclipse 更为紧密的集合,Abbot 目前已经以 Eclipse 插件的形式开发,Abbot
对 SWT 的支持是通过 Abbot SWT 插件来实现的。目前 abbot 的 SWT 插件尚未正式发布,我们将指引你从 CVS
上获取一个可用版本,目前的代码已经能够支持绝大多数的 SWT 和 JFace 构件的测试。笔者在一个项目中使用了数十个基于 Abbot
的 UI 测试用例,效果良好。实践证明,在 Eclipse RCP 和插件项目中,通过 Abbot 和 JUnit 的结合,构建用户界面的自动化测试用例,可以极大的减少测试人员重复的用户界面测试工作。
本文将带领读者走入 Abbot 的世界,学习使用这一有力的工具来增加我们插件开发的工作效率,在全面的介绍Abbot之前,我们先从一个简单的测试用例,感受一下
Abbot 的非凡魅力。
新手上路:开始一个简单的 Abbot SWT 测试
这一部分将介绍 Abbot SWT 插件的下载和配置,给出一个简单的测试用例使读者对 Abbot
SWT 有个感性的认识,然后通过分析该测试用例来介绍 Abbot 的基本概念,使读者能够“观其大略”。本文所有的示例代码都在 Eclipse
3.2.1,JDK1.5 和 JUnit3.8.1 环境下通过测试,请读者先准备好开发环境。
Abbot plugin 测试环境配置
目前 Abbot SWT 的插件尚在开发过程中,没有可用的发行版本,我们将从 CVS 上获取源码。首先启动
Eclipse,指定一个新的空白的 WorkSpace,配置 Abbot 的 CVS 仓库,具体配置信息参见 图 1,使用匿名用户,无需输入密码即可。
图 1:Abbot 项目的 CVS 配置信息
点击确定以后打开 CVS 仓库的 HEAD,同时选中 abbot、abbot.swt 和 abbot.swt.eclipse
三项,点击右键,在弹出菜单中选择“check out”,下载被选中的三个插件项目。
切换到 PDE 透视图,你可以看见 WorkSpace 中的三个 Eclipse 插件,其中
abbot 插件是基础的插件,具有 Abbot 的基础功能和 AWT/Swing 的界面测试功能;abbot.swt 插件是在
abbot 基础上的扩展,增加了对 SWT 的支持;而 abbot.awt.eclipse 则在 abbot SWT 的基础上增加了对
Eclipse 插件测试的支持,比如一些常用的针对 Eclipse 的实用工具、JFace 对话框的测试支持等。
视你的 Eclipse 的环境不同,你可能需要做一定的配置才能保证编译通过,请不要介意那么多的
warning,因为你使用的是正在开发中的源代码。为了便于读者使用,笔者在附件中也附加了这三个插件及其源码,读者也可以直接下载,然后导入到
Eclipse 工作区中。
现在你的工作区中的三个项目已经通过编译了,下面我们将用一个简单的例子来展示 Abbot SWT
的用法和基本概念。
开发一个简单的测试用例
为了简化步骤,我们的测试用例将简单的测试 Eclipse 的新建 Java 类向导,这样做可以避免我们编写被测试代码。我们将创建一个测试插件,并在该插件中创建一个测试用例来执行新建
Java 类向导的界面测试。你可以遵循以下步骤来创建和运行该测试用例。
1. 创建测试插件
在刚刚配置好的包含 Abbot 插件的工作区中新建一个插件项目,命名为 AbbotTest,所有选项采用默认设置,给该插件增加如图
2 的 Dependency:
图 2: AbbotTest 插件的 Dependencies
请确认选用了 JUnit 的 3.8.1 版本,使用更高版本的 JUnit 可能会引起一些问题,本文的测试用例在 JUnit
3.8.1 版本上能够通过所有测试。
2. 在测试插件中创建测试用例
在该插件中新建一个 Java 类,类名为 JavaWizardTest,包名为 abbottest.sample,该类的
Java 代码如表 1 所示。
清单 1. JavaWizardTest.java 的代码
package abbottest.sample;
import junit.framework.TestCase;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Widget;
import abbot.finder.matchers.swt.ClassMultiMatcher;
import abbot.finder.matchers.swt.TextMatcher;
import abbot.finder.matchers.swt.TextMultiMatcher;
import abbot.finder.swt.BasicFinder;
import abbot.finder.swt.TestHierarchy;
import abbot.tester.swt.ButtonTester;
import abbot.tester.swt.MenuItemTester;
import abbot.tester.swt.Robot;
import abbot.tester.swt.TextTester;
import abbot.tester.swt.WidgetTester;
public class JavaWizardTest extends TestCase
{
public void testJavaWizard() {
final Thread wizMain = new Thread() {
public void run() {
WidgetTester.waitForShellShowing("New Java Class");
findAndTestWizard();
}
};
wizMain.start();
openJavaWizard();
}
private void openJavaWizard() {
MenuItemTester menuItemTester = (MenuItemTester) WidgetTester.getTester(MenuItem.class);
menuItemTester.actionSelectMenuItem("&File/&New\tAlt+Shift+N/Class",null,
Display.getCurrent().getActiveShell(), 1000);
}
private void findAndTestWizard( ) {
TestHierarchy hierarchy = new TestHierarchy(Display.getCurrent());
final BasicFinder finder = new BasicFinder(hierarchy);
try {
final Widget root = finder.find(new TextMatcher("New
Java Class"));
final Text nameText = (Text) finder.find(new ClassMultiMatcher(Text.class,
4));
final Button finishButton=(Button)finder.find(root,
new TextMultiMatcher("&Finish",1,Button.class));
final Button cancelButton=(Button)finder.find(root,
new TextMultiMatcher("Cancel",1,Button.class));
abbot.tester.swt.Robot.syncExec(root.getDisplay(), null, new
Runnable() {
public void run() {
TextTester textTester = new TextTester();
textTester.actionEnterText(nameText, "classname");
ButtonTester buttonTester= new ButtonTester();
Robot.delay(1000);
assertFalse(finishButton.isEnabled());
buttonTester.actionClick(cancelButton);
}
});
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
} |
从清单 1 中我们可以看出,JavaWizardTest.java 就是一个普通的 JUnit
测试用例,不过在测试方法里面使用了不少 Abbot 的 API。以上代码可以简单地演示如何测试 Eclipse 的新建 Java
类向导的一些特性,它使用到了 Abbot 提供的一些测试类,并通过启动新的 UI 线程对用户界面进行测试。具体代码的含义,我们将在下文介绍,这里主要希望运行这个测试用例来快速展示一下
Abbot SWT 的简洁用法。
3. 运行该测试用例
在“Package Exploer”视图中右键选中 JavaWizardTest.java,在右键菜单中选择“Run
As -> JUnit Plug-in Test”,静静等待片刻。你将看见在新启动的 Eclipse Runtime 界面中,我们的测试用例自动的打开了新建
Java 类向导,并执行了我们预先定义的操作,输入一个类名,JUnit 执行断言,断言通过,取消该向导,测试成功。整个测试过程简单而快速,如果手工去做,可能需要点击多次鼠标和键盘,对于实际应用中复杂的用户界面,重复的手工劳动就不堪胜任。使用
Abbot,你可以轻松地重复执行标准化的测试,这正是自动化测试工具的优点。
以上的例子让我们了解到 Abbot 的用法也是相当简单的,我们只需要在 JUnit 测试用例中增加
Abbot API 的调用,就能捕获界面上的构件(Widget),通过 Abbot API 我们可以触发界面动作,获取用户界面的执行结果,并作出断言来判断界面的运行是否符合我们的期望。就是这个简单测试用例,涵盖了大部分的
Abbot 的基本概念和框架的主要用法,下面我们会逐一介绍。
Abbot 基本概念
我们将通过对以上测试用例的分析来向读者展示 Abbot 的基本概念,首先从最简单的部分入手来考察以该测试用例,我们选择
openJavaWizard 方法作为入手点,该方法使用了 MenuItemTester 类的 actionSelectMenuItem
方法,MenuItemTester 是 Abbot 众多的 Tester(我们称之为测试器)的一种,我们称为菜单项测试器,菜单项测试器的
actionSelectMenuItem 方法能够激活菜单栏的菜单项,就像我们鼠标选择该菜单项一样。根据我们的路径参数“&File/&New\tAlt+Shift+N/Class”,菜单项测试器找到我们期望的菜单项
--“新建 Java 类”菜单,从而打开“新建 Java 类”的向导。这里需要注意的是不同版本的 Eclipse 或者不同的透视图下,菜单项的路径是会不一样的,在笔者的
Eclipse 3.2.1 环境中,菜单项如 图 3 所示,因为 Abbot 完全是依赖文本的匹配去寻找 UI 构件,因此,其他情况下以此类推。
图 3. Eclipse 3.2.1 的菜单项
基于 图 3 的菜单项,我们菜单路径中的第二项子菜单才会出现“&New\tAlt+Shift+N”这样的路径,如果读者运行测试时在该方法内遇见“Widget
not found ”或者超时的错误,你可能需要检查一下 Eclipse Runtime Workbench 的菜单是否和代码一致(不同版本的可能略有不同),如果不一致,稍加修改菜单项的路径参数就能使测试通过。
这里我们接触到的第一个概念就是 Abbot 的 Tester,我们称之为测试器,测试器用于执行不同的
UI 构件测试,可以用于触发 UI 构件的相应动作,效果和使用鼠标操作界面一样,只不过是由代码触发,这样就可以在测试代码中控制用户界面的行为,达到用户界面自动化测试的目的。如
清单 1 所示,通过使用菜单项测试器,openJavaWizard 方法中简单的两行代码就能打开我们需要测试新建 Java 类向导。
下面再看测试代码的主体部分,也就是 testJavaWizard 方法,读者也许奇怪该方法中代码的写法,我们将其摘录在
清单 2 中。
清单 2:testJavaWizard 的方法体
final Thread wizMain = new
Thread() {
public void run() {
WidgetTester.waitForShellShowing("New Java Class");
findAndTestWizard();
}
};
wizMain.start();
openJavaWizard(); |
该方法之所以要使用线程,并且使用一种先等待,后触发的怪异方式,主要是因为 SWT 要求对 UI
的操作在新的线程中进行,同时 Eclipse 会启动新的 UI 线程来打开向导,我们很难保证打开向导后刚好能够执行后续的操作,也就很难保证顺序地同步地执行
UI 的测试。使用这种特有的“等待-触发”方式,就能保证测试的顺序满足我们的需求。以上代码展示了我们先启动一个测试线程在等待一个名为“New
Java Class”的 shell(也就是新建 Java 类向导),然后执行 openJavaWizard 方法,一旦该方法能打开向导,等待线程就能捕获到,自然就会执行
findAndTestWizard 方法进行对向导的测试。启用线程等待对话框或者向导,然后执行对他们的测试是使用 Abbot 时非常常用的一种方法,我们会频繁的在测试方法中使用这样的代码结构。默认情况下,线程的执行是同步的,所以我们不用担心测试用例会在线程运行结束前结束。
了解这一点之后,我们就可以看看findAndTestWizard方法是如何进行测试,如同方法名所暗示的那样,它会先在界面上找到一些UI构件,然后测试这些构件。该方法的前两句(见
清单 3)是初始化一个BasicFinder,这是Abbot的数个Finder中的一种。Finder,我们称为查找器,它需要和匹配器(Matcher)一起协同工作,查找器和匹配器相配合就能在给定的UI阶层体系中寻找到目标构件。
清单3:新建一个查找器
TestHierarchy hierarchy
= new TestHierarchy(Display.getCurrent());
final BasicFinder finder = new BasicFinder(hierarchy); |
通过清单 3 的代码我们生成一个查找器,通过查找器我们可以找到相应的用户界面的构件,如清单4的代码所示。
清单 4:使用查找器查找 UI 构件
final Widget root = finder.find(new TextMatcher("New Java
Class"));
final Text nameText = (Text) finder.find(new ClassMultiMatcher(Text.class,
4));
final Button finishButton=(Button)finder.find(root,
new TextMultiMatcher("&Finish",1,Button.class));
final Button cancelButton=(Button)finder.find(root,
new TextMultiMatcher("Cancel",1,Button.class)); |
找到界面上的构件,就可以让这些构件执行相应的动作,这就需要用到相应构件的测试器,在表 x 所示的测试代码中,我们首先创建文本测试器,然后可以在找到的文本框中输入文本,并创建按钮测试器,判断完成按钮是否被
Disable,然后我们取消该向导,代码如 清单 5。
清单 5:对向导用户界面的测试代码
TextTester textTester =
new TextTester();
textTester.actionEnterText(nameText, "classname");
ButtonTester buttonTester= new ButtonTester();
Robot.delay(1000);
assertFalse(finishButton.isEnabled());
buttonTester.actionClick(cancelButton); |
用户界面测试的常见的形式包括要判断构件是否正确生成、构件的状态和动作是否符合预定的需求、构件的数据是否满足测试的要求等等。
需要注意的是,SWT 对在线程中访问UI构件有特殊的要求,而我们的测试代码是在一个线程中访问UI的构件,我们需要将这些代码置于
Runnable 的 run 方法体内通过 abbot.tester.swt.Robot.syncExec执行, 否则会抛出“Invalid
thread access”的异常。至于“Robot.delay(1000);”这条语句,主要是保证一定的延时,因为 Abbot
的测试执行过快,如果测试者希望亲眼看着测试一步一步的进行,就可能需要多增加一些这样的语句。
此时重新品味一下测试代码,你也许会不以为然(如果你能耐心读完本文,你就不会这样想),Abbot的用法非常的简单,无非是找到一些代测试的构件,执行相关的动作,比较测试的结果,这有何难?实际上这个例子是我们为了演示经过简化的,以上的测试代码虽然很简单,如果组合使用这些简单的逻辑,就能够测试很复杂的界面。就像你为所有重要的功能编写了单元测试一样,我们建议你为所有重要的界面编写测试用例,尤其对于一些数据敏感的动态生成的用户界面,Abbot的测试非常重要。但是,我们不推荐像单元测试一样写纯界面的测试,在单纯测试UI的同时,你可以通过UI的动作来测试业务逻辑,通过端到端的测试用例来实现业务功能的测试,除了自动化程度高以外,还可以避免代码的改变和业务逻辑的改变带来的测试用例的改变。对于一个设计良好的Eclipse插件,核心的用户界面的变化频率应该远远的低于业务逻辑的变化,因此通过界面去测试业务逻辑是很好的一种选择。选择重要的流程,通过Abbot构建端到端的测试用例,能够覆盖到绝大多数的业务流程,这样的测试能够很好的测试系统的业务功能,并极大的减少重复劳动,提高测试的效率。如果读者使用Eclipse平台开发过RCP业务系统,一定会深有这样的体会。
在深入的掌握 Abbot 的复杂用法之前,我们先来读读 Abbot 的代码,研究一下 Abbot
的原理,这样做符合一个 XP 程序员的风格。
抽丝剥茧:Abbot SWT 的体系结构和工作原理
通过以上的测试用例和概念介绍,你一定已经对 Abbot SWT 有了感性的认识,一个看似简单的测试用例,实际上并不简单,几乎包含了
Abbot 的所有主要内容。现在让我们继续深入下去,看看 Abbot SWT 的体系结构和工作的原理,以便更深刻的了解、掌握和使用它。
Abbot 测试器
我们首先从 Abbot 测试器开始,Abbot 测试器可以帮助我们对各种不同的UI构件进行测试,JavaWizardTest
测试用例使用到了文本测试器(TextTester)、按钮测试器(ButtonTester)、菜单项测试器(MenuItemTester)和通用的构件测试器(WidgetTester)。Abbot
为几乎所有的 SWT 构件提供了相应的测试器,我们可以从图 4 上看到这一点。
图 4:Abbot 提供的所有的 SWT 部件的测试器
从图 4 可以看出,Abbot SWT 的测试器相当的丰富,仅有少数的复合构件及 JFace 构件如 Section、Browser、Dialog
等没有测试类。但是这些复合构件都是由基本的UI构件组成的,我们可以通过简单的UI构件的测试完成符合构件的测试。当然你可能需要研究这些构件的源代码,才能找到组成他们的基本构件,从而使用相应的测试器对其进行测试。例如
对于Section,这个复杂的UI构件,目前Abbot并没有提供“SectionTester”,但Section的标题栏实际上是一个Label,
你可以使用查找器根据Section的标题找到Label,然后调用 LabelTeseter的测试方法actionClick来打开或者关闭一个Section,有兴趣的读者可以试试,这是笔者在实际项目中遇到的一个小问题,其他的问题可以类似的方法解决。
和几乎所有的JavaGUI 测试工具一样,所有的测试器最后都是通过java.awt.Robot的API去激活用户界面,我们可以通过查看Abbot
SWT的源码,最终可以一直追溯到 java.awt.Robot 和RobotPeer,这正是JDK中里面为了方便界面测试提供给程序员的底层API,可见所有的Java图形用户界面测试工具无不是扩展自这个Robot。java.awt.Robot可以生成操作系统原生的事件和消息来创建自动测试,自运行的演示,或者出于其他目的需要让应用来控制鼠标和键盘,用途很是广泛,有兴趣的读者可以深入研究。
Abbot 查找器和匹配器
虽然通过测试器可以发出消息驱动UI测试的完成,但是如果没有查找器的帮忙,你很难获取到你要测试的构件的句柄。我们已经了解到Abbot主要是依靠查找器(Finder)和
匹配器(Matcher)去寻找测试目标,尽管他们在 Abbot的基础插件中已经有了实现,Abbot SWT插件还是要为SWT开发了专门的查找器和匹配器。我们可以通过图
5 了解Abbot SWT的查找器和匹配器的关系:
图5 :Abbot SWT的查找器和匹配器
如图,我们最常用的是BasicFinder和匹配器的配合,通过参数配置,BasicFinder可以支持广度优先和深度优先的查找。
如图 6,考虑到不同的需求,Abbot SWT提供了不同种类的匹配器,他们都实现了Matcher接口,如果有特别的需求,你也可以自行实现或者修改现有的匹配器的代码。
图6:Abbot SWT的匹配器
图 6 中展示了很多不同用途的匹配器,我们经常会使用 ClassMultiMatcher 和 TextMultimatcher。如果我们仔细的看看代码就明白
Abbot 是如何能够找到目标构件的,打开 abbot.finder.swt.BasicFinder 类,我们会看见 Abbot
会遍历 Hierarchy 上面的所有 UI 构件,直到找到匹配器的条件满足的构件返回。匹配器是如何匹配的呢?我们可以简单的看看
TextMatcher 的代码,在 TextMatcher 的 matches 方法中充满了诸如清单7中的判断代码。
清单 7:TextMatcher 的代码片断。
if (w instanceof Button)
{
setWtext(((Button)w).getText());
}
if (w instanceof Combo) {
setWtext(((Combo)w).getText());
} |
这说明所有TextMatcher对于不同的构件会有不同表现,比如 button就是 button的text,combo是选中项的text而tableItem的text则是所有列的text的一个数组。了解这些代码对你构造匹配器有着重要的意义,只有因势利导,你才能更好的使用Abbot。经常会有初学者将NameMatcher和TextMatcher
混淆,如果看看NameMatcher的代码就了解它是匹配构件的类型和变量名,而不是构件的文本。
细心的读者也许会发现一个问题,Abbot的匹配器过多的依赖于字符串的匹配,这要求最好所有的界面上的文本全部使用常量的方式定义(否则在不同的语言环境中,你的测试用例将寸步难行),这也符合Eclipse国际化的编程要求,可见使用Abbot测试用户界面,会迫使你编写国际化的插件(我们的新建java类测试用例为了简化,就没有做类似的处理)。
这里有个有趣的话题,我们可以通过使用键盘的快捷键避免使用太多的查找器,菜单的快捷键,Tab键和回车键的组合使用经常能够节省你不少的时间去寻找按钮和菜单,通过WidgetTester.actionKeyPress方法,你可以轻易的模拟键盘事件。同时这也是对你用户界面的Accessibility(易访问性)的极端测试,完全键盘操作是Eclipse界面设计的Accessibility的一项要求。如同我们刚刚提到的国际化的要求一样,这里我们的测试用例反过来能够对代码的质量提出一些强制要求,可见极限编程方法中优先编写测试用例的指导方针果然名不虚传(当然本文提到的国际化和易访问性只是一个无心插柳的副作用,优先编写单元测试代码会强制你的代码简单易读,接口和业务逻辑代码分离,层次清晰,结构明确,并迫使你重构代码,使设计更加细化。有兴趣的读者可以参考《重构,改善既有代码的设计》一书)。
Abbot 测试代码的同步执行
Java 语言本身就提供了多线程机制,因为很多的用户界面会通过不同的线程完成不同的任务,有些线程是同步的,有些线程是异步的,你很难保证你测试代码会被同步的执行。SWT要求对UI的操作都要放在新的线程中进行,在我们的JavaWizardTest测试用例中,我们必须使用新的线程去测试界面,同时为了保证测试的同步,我们要等待向导的出现,然后才能执行针对向导的测试代码。读者也许已经注意倒我们的测试用例中openJavaWizard这一方法并未在线程中被调用,那是因为在MenuItemTester中的actionSelectMenuItem操作中,选择菜单的操作已经启动了一个新的线程。
在我们的等待线程中,我们如果要执行UI构件相关操作的断言,就应当都把他们封装在一个Runnable里面使用“abbot.tester.swt.Robot.syncExec”保证他们被同步的执行,这最终使用到了“org.eclipse.swt.widgets.Dispaly”的syncExec方法。由于SWT单独有一个线程(主线程)处理界面显示,数据显示等,如果要在其他线程中操作界面元素,就必须使用Display的syncExec和asyncExec两个方法执行,即将另外线程的操作交给主线程处理,我们使用的syncExec方法表示要顺序的同步的执行相关的测试操作。对于形如“assertFalse(finishButton.isEnabled())”这样的断言,因为涉及倒了UI构件的操作,就需要包装在syncExec方法内,而形如”
assertNotNull(finishButton)”这样的断言,则不需要任何包装,直接在测试线程的代码体内就可以执行。
研究 Abbot 的源码可以发现,Abbot 的测试器代码中都使用了 syncExec,所以我们唯一需要使用的地方就在执行UI构件相关的断言的地方,但是为了保证代码的统一和完整,我们尽量使用形如如本测试用例的写法。
在Abbot控制用户界面的测试同时,请不要使用鼠标或者键盘,同时尽量关闭可能会弹出对话框的后台程序,以免使
Abbot 失去用户界面的控制权。不过即使被别的用户界面打断,在有效的等待时间的内,你仍然可以手工帮助界面运行到等待线程的条件处,Abbot会检测到界面并能继续执行下去。如果你在测试
Eclipse RCP 应用,界面的产生可能会和网络条件或者数据量有关系,Abbot默认的等待时间可能不能满足需要。当在默认的时间到达前没有能够等到期望的界面时,Abbot
会抛出 WaitTimedOutError 异常。Abbot 默认的等待时间应该是一分钟,其值在 abbot.tester.swt.Robot
中有定义,见清单 8。
清单 8. 默认延时的定义
protected static int componentDelay
=
Properties.getProperty("abbot.robot.component_delay",defaultDelay,
0, 60000); |
你也可以通过设置延时参数来调整你的测试代码,WidgetTester提供了一些等待方法,其中就可以通过参数来设置延时时间,见图
7。
图 7:WidgetTester的等待方法
如果你有特别的需要,不仅满足于等待对话框或者构件的出现(在RCP应用中常见的就是等待服务器端的返回数据),可以使用abbot.tester.swt.Robot的“wait(Condition
condition)”方法。你只要实现自己特定需求的Condition接口就可以让用户界面在等待你期望的结果,如清单9所示,Condition接口相当的简单。
清单 9:Condition接口的定义
public interface Condition {
/** Return the condition state. */
boolean test();
/** Return a description of what the condition is testing. */
String toString();
} |
你需要在 test 方法中检查条件,一旦条件满足就返回 true,否则返回 false, Abbot
的 wait 方法会不断去调用 test 方法查询条件是否满足,你在调用时设置超时条件(如 图 7 中的”wait(Condition,long)”方法),如果不设置,Abbot
仍然会使用默认的等待超时值。
参考资料
从 Abbot SourceForge 主页上获取大量的示例和教程。
访问 Abbot CVS 仓库配置,获取最新版本软件。
关于作者
赵勇,IBM 中国软件开发实验室 IBM 中国 SOA 设计中心工程师。具有多年的 J2EE
和 Web Service 开发经验,目前专注于 SOA 项目实践和相关的理论,工具的研究和开发。对 ESB、SCA、BPEL、自动化测试和极限编程等技术有浓厚的兴趣。联系方式:zhaoyong@cn.ibm.com。 |