[转]使用 SWTBot 为您的 eclipse 应用创建自动化 GUI 测试用例

转载:

http://www.ibm.com/developerworks/cn/opensource/os-cn-ecl-swtbot/

SWTBot 是一个年轻的开源项目,致力于简化 SWT 和基于 eclipse 的富客户端应用的 GUI 测试,平台独立,功能强大。该项目已经被接纳到 eclipse.org 基金会,虽然目前尚处于孵化阶段,但已经成功地应用于很多产品的测试了。本文详细地介绍了如何配置开发环境,并通过实例、类图等分析了 SWTBot 的设计和实现结构。

配置基本的开发环境

本文所使用的开发环境是 Eclipse 3.5 的用于 RCP/Plug-in 开发的套件,您可以通过在线更新直接安装最新版本的 SWTBot 插件。

依次选择 eclipse 菜单项“Help-> Install New Software …”,在弹出的窗口中添加更新站点,如图 1 所示,目前的站点地址是http://download.eclipse.org/technology/swtbot/galileo/dev-build/update-site/

图 1. 添加更新站点

图 1. 添加更新站点

在可行的插件列表中,如图 2,分别包括 SWTBot SWT 测试工具、eclipse 测试工具和 GEF 测试工具,在本文撰写阶段,GEF 功能还没有真正地集成进来。选择您希望安装的插件,并点击“Finish”进行安装。

图 2. 安装插件

图 2. 安装插件

如果您希望获取 SWTBot 的源代码,可以通过 SVN 或者 Git 获取,这里有更详细的代码库信息,不再介绍。

经过上面的步骤,开发环境就已经搭建好了,您是不是有些迫不及待地要尝试下 SWTBot 的功能了,我们首先从一个简单的测试用例开始吧。

 

创建您的第一个 SWTBot 测试用例

简单起见,我们就模拟一个为 eclipse 添加更新站点的过程,具体步骤如前文所描述的安装 SWTBot 插件的过程。

1. 创建测试工程

首先,您需要创建一个 eclipse 插件工程,把 SWTBot 相关的插件添加到依赖关系中,详细信息请参考图 3

图 3. 插件依赖关系

图 3. 插件依赖关系

2. 新建测试用例

新建一个 Junit 4.x 测试用例,将下面的代码添加到您的用例中。因为不能重复添加站点,为了能够重复执行,例子在最后阶段选择了取消操作。

清单 1. 测试代码
 package myswtbot.test; 

 import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot; 
 import org.eclipse.swtbot.swt.finder.SWTBotAssert; 
 import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner; 
 import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell; 
 import org.junit.AfterClass; 
 import org.junit.BeforeClass; 
 import org.junit.Test; 
 import org.junit.runner.RunWith; 

 /** 
 * My first SWTBot test case which stimulate a scenario 
 * of adding updating site for the eclipse. 
 * The update site is for SWT development tools. 
 * 
 */ 
 @RunWith(SWTBotJunit4ClassRunner.class) 
 public class AddUpdateSiteTest { 

   private static SWTWorkbenchBot bot; 

   @BeforeClass 
   public static void setUpBeforeClass() throws Exception { 
      bot = new SWTWorkbenchBot(); 
      bot.viewByTitle("Welcome").close(); 
   } 


   @Test 
   public void testAddUpdateSite() throws Exception { 
      bot.menu("Help").menu("Install New Software...").click(); 
      SWTBotShell shell = bot.shell("Install"); 
      shell.activate(); 

      bot.button("Add...").click(); 
      //find the new shell widget by its name 
      SWTBotShell shell1 = bot.shell("Add Site"); 
      shell1.activate(); 

      bot.textWithLabel("Name:").setText("SWT development tools"); 
      bot.textWithLabel("Location:"). 
 setText("http://www.eclipse.org/swt/updates/3.5"); 

      //verify button status 
      SWTBotAssert.assertEnabled(bot.button("OK")); 

      //Cancel it, in order to execute again and again 
      bot.button("Cancel").click(); 
      bot.button("Cancel").click(); 
   } 

   @AfterClass 
   public static void tearDownAfterClass() throws Exception { 
		 bot.sleep(5000); 
	 } 

 }

您可能已经注意到,本文给出的测试用例,单独指定了 Classloader。SWTBot 的测试用例基于 Junit 4 测试框架,但是不同于 PDE-Junit 测试用例,它需要利用 SWTBotJunit4ClassRunner 来执行,因为普通的 PDE-Junit 测试用例与被测试的界面运行在同一个线程,而 SWTBot 测试用例发送给被测界面的一些事件是阻塞的,如果运行在同一线程会导致测试用例停滞。

3. 执行测试用例

选中要执行的测试用例,选择 eclipse 的主菜单“Run ->Run Configuration”,操作步骤可能根据您选用的 eclipse 版本会有区别。选择执行的应用,具体您可以参考图片 4。

图 4. 运行配置

图 4. 运行配置

万事俱备,开始执行用例吧。您可以看到,一个 eclipse 应用被启动起来,然后 SWTBot 模拟了如何添加更新站点的工程,并且对一些用户关注的测试点,例如,按钮状态,文本信息等进行了验证。从这个用例我们对 SWTBot 有一个简单的印象,它采用了 eclipse 插件工程的结构,并采用 Junit4 框架和 eclipse 本身的运行机制,我们将会在下面的章节继续探讨它的更多细节。

 

SWT 的结构和特性

首先了解一下 SWTBot 的组成,目前 SWTBot 主要包括 3 个部分,分别适用于 SWT 测试、Eclipse 测试和 GEF 应用测试。SWT 部分可以看作是测试框架的基础,提供了 SWT 控件的代理类、查找器、匹配器等。Eclipse 部分提供了对 Perspective/view 等 eclipse 特性的支持,但是实现的结构是基本一致的,您在开发用例时可以采用同样的编码思路。

SWTBot 基本结构

下面的图 5,说明了 SWTBot 的基本结构,类 SWTBot 提供了各种方法以获取目标控件的代理类 (Widgets),出于简单考虑,这里仅列出了部分查找器(Finder)和匹配器(Matcher)实现,查找器按照一定条件来定位目标控件,而匹配器则是支持了强大的表达式功能,如果您深入查看各种匹配器的实现细节,就会发现它利用了 Hamcrest 匹配库,有兴趣的话您可以在到 google code上获取项目细节。

图 5. SWTBot 基本结构类图

图 5. SWTBot 基本结构类图

更多细节

几乎全部(目前的版本还有部分未实现的)SWT 控件(Widget),在 SWTBot 中都有对应的代理类,图 5 仅列出了一个按钮控件的示例,可以在 org.eclipse.swtbot.swt.finder.widgets 包下找到其他实现。您的 SWT 知识能够帮助您很快的熟悉 SWTBot 的结构,图 6 是 SWT 和 SWTBot 对应类的结构对比,SWT 中的 Widget 子类对应的代理类扩展了 AbstractSWTBot 抽象类,Control 子类对应的代理类扩展了 AbstractSWTBotControl 类。这些抽象类中实现了一些测试中通用的方法,如模拟鼠标动作,检查控件状态等。

图 6. SWT 和 SWTBot 部分类的结构对比

图 6. SWT 和 SWTBot 部分类的结构对比

验证点是测试中的一个重要组成部分,单单模拟操作并不能达到测试的目的,我们需要针对关注的细节添加验证点。您可以利用 Junit 提供的传统断言方式,也可以使用 SWTBot 额外提供的断言方法。针对 GUI 测试的特点,SWTBot 框架在 SWTBotAssert 类中实现了部分断言方法,我们在 AddUpdateSiteTest 中验证按钮状态就是利用了其提供的方法,图 7 提供了具体的介绍,您可以根据需要选择常规验证和正则表达式验证等等。SWTBot 还提供了快照功能,在用例发生失败的时候可以截取屏幕显示并保存到图片文件,这样您就可以直观的发现导致错误的问题了。

图 7. SWTBot 断言方法

图 7. SWTBot 断言方法

您在测试中,可能经常会遇到超时处理、等待其他线程状态等问题,传统的方式是开发人员在代码里自己去处理线程的事务,这就无形中增加了学习的难度和使用的风险。这种随意的方式,会带来潜在的问题,比如您自己调用线程 API 去检查超时,一旦被测产品行为改变,例如因为不同的操作系统或者代码变更,这时您需要去用例中调整超时的参数和代码,非常不便。SWTBot 可以帮您解决大部分这种问题,您无需费神去操作线程的细节,图 8 就是对 SWTBot 的相关实现的一个说明,通过 ICondition 接口和其实现类,SWTBot 提供了非常完善的操作方式。如果目前的实现无法满足您的特定需要,也可以直接调用 Conditions 工厂类中的方法,自己去创建条件实例。

图 8. SWTBot 的 IConditions

图 8. SWTBot 的 IConditions

实际应用的角度

在具体的测试用例开发中,SWTBot 可以作为您操作 SWT 控件的一个入口,如果您需要测试的是一个普通 eclipse 应用,那么可以参考前面介绍的 AddUpdateSiteTest 用例那样,从 SWTWorkbenchBot 对象开始,通过 Bot 对象的方法找到目标控件,然后通过目标控件的代理对象,您就可以模拟鼠标、键盘等操作了,也可以获取目标控件的状态信息。这里有一些小细节,一般来说,可以认为 GUI 对象是树状结构的,通过指定恰当的父对象作为构造函数的参数,可以更加快速地找到目标控件,您可以通过这一点提高 SWTBot 的查找效率。

SWTBot API 非常简单、易用,代码的可读性也非常好,您可以看下面图 9 中列出的 SWTBot 查找 Button 控件代理类的方法,不要诧异,方法的功能就如您看到的名字,其他的控件也同样可以通过 tooltip,text,ID 等简单条件查找。由于完善的定位控件的方法,不需要了解查找器或者匹配器的细节就可以完成您的大多数测试需求。

图 9. SWTBot 部分方法示例

图 9. SWTBot 部分方法示例

在执行前面的测试用例的时候,如果您觉得执行的速度太快了,您可以定义脚本回放的间隔等参数来控制执行速度。SWTBot 提供了简单易用的配置入口,您可以通过修改 SWTBotPreferences 类的静态参数来达到这个目标,一些默认值也可以通过设置环境变量来修改。

为方便生成脚本,常见的图形界面测试工具通常支持录制的方式来创建脚本,即通过记录器(Recorder)来记录您的动作。SWTBot 有一个不是非常完整的记录器实现,不幸的是,在最近的版本中(笔者使用的是 2.0),记录器已经被移出 SWTBot 安装包,如果您确定自己非常需要记录器,可能不得不退回到 1.3 版。不过从图形界面测试实践的角度来看,使用记录器生成的脚本在代码复用、可维护性等方面也许并不是一个非常好的方法。抛却这些测试理论的考虑,现实的问题是,如果直接书写脚本,需要有一定的 SWT 控件和 Eclipse 界面知识,比如,您可能不了解要测对象具体是什么类型的。如果您有这样的困难,可以使用 SWTBot 自带的 EclipseSpy 视图(通过热键 CTRL+SHIFT 可以激活该视图),它会把您鼠标指到的控件信息详细的列出来。当然,您也可以借助 SWT Development Tools工具包或者 eclipse 自带的 Plug-In spy 的帮助来完成测试用例开发,有关这些工具的使用,您可以参考相关文档,本文就做进一步介绍了。

 

总结

通过前面的介绍,相信您对 SWTBot 的功能已经有了一定的了解,它强大的测试功能、代码优异的可维护性、可读性等令人印象深刻,相信可以作为您测试 SWT、Eclipse 插件和 RCP 应用的一个不错的选择。

猜你喜欢

转载自topmanopensource.iteye.com/blog/1971260