内容


Rational Functional Tester 的高效测试自动化技巧

Comments

如果您经常使用测试自动化操作工具,那么您可能对测试自动化框架的概念十分熟悉。测试者们会经常寻找一些建议、参考,以及解决方案,但是框架只是您所需要考虑内容的一半。如何构建您的测试代码,使您所测试的应用软件的测试过程最便利取决于有效自动化操作的第二个步骤。

这篇文章重点强调第一个步骤,它可以帮助您理解如何有效地使用您所拥有的工具。这个步骤包括以下几个论题:

  • 对象和属性
  • 使用浏览器的常见问题
  • 验证点
  • 低级的指令
  • 脚本帮助器超类

对于每个论题,您可以在这篇文章末尾的参考资源中找到相关附加信息的连接。

注意:
作者是利用以下软件来编写这篇文章的:

  • IBM® Rational® Functional Tester Version 7.0.0
  • Microsoft® Internet Explorer® Version 6.0.2900.2180,SP2
  • Microsoft® Windows® XP Professional,SP2

查找对象及其属性的替代方案

像对话框、命令按钮,以及标签这样的组件都有相关联的一些信息称作属性。这些属性都有自己的名称和值。您经常需要接触您所测试的对象的各种不同的属性,这样您可以执行一些类型的验证,或者您可以按照程序决定测试脚本下一步要做什么。这个部分阐述了对象,属性,以及与您的脚本相吻合的方法。

查询并设置对象属性的值

您有没有想过在运行时间将先前版本的值与当前的值动态地进行比较?或者您是否想过将一个分支添加到您的基于包含于一个对象中的属性当前值的 Rational Functional Tester 脚本中去? 您可以通过程序化地调用 getProperty 程序来重新获取一个属性的值。

代码列表 1 中的例子使用了 getProperty 程序来确定一个标签是否包含一个成功消息。如果包含,那么就可以点击 OK 按钮。如果不包含,那么就要点击 Cancel按钮。

列表 1:利用 getProperty 方法
if("SUCCESS".equals(dialog_htmlDialogStatic().
getProperty(".text")))
{
dialog_htmlDialogButtonOK().click();
} 
else 
{
dialog_htmlDialogButtonCancel().click();
}

如果您要算出一个对象有那些属性,您可以打开 Test Object Map,可以在那里查看到可利用的属性。(参见图 1)

图 1. 列在 Test Object Map 中的属性
图 1. 列在 Test Object Map 中的属性
图 1. 列在 Test Object Map 中的属性

您还可以通过临时记录一个 Object Properties 验证点(VP)或者通过 VP and Actions 向导插入这个指令来提取一个属性值到一个变量中。

注意:
Rational Functional Tester 还支持一个 setProperty 方法。然而,那个方法却有一个放弃声明:不要使用它除非您能确定这个结果。这是因为它调用了内部的方法,这种方法可能干扰您测试的应用软件的完整性。

现在您已经了解如何从您的对象中获取属性,但是您可能回有这样的疑问:“我如何才能优先找到这个对象呢?”这是一个很好的问题。

搜索 TestObjects 的方法

您的 Rational Functional Tester 脚本的基本构建块到处都存在 TestObject一个 TestObject 代表重新运行这个应用脚本与您正在测试的应用软件之间的一个连接点。对于产生测试脚本中的每个 TestObject,一个相应的对象存在于这个您所记录的相应的应用软件中,并且这个对象同时也存在于 Test Object Map 中。

很可能的是,您通常会利用这个对象图与 TestObject 产生相互作用。然而,Rational Functional Tester 还支持一个程序化寻找 TestObject 位置的方法。这种搜索是基于一对代表 TestObject 或者您要查找的 TestObjects 属性的名称和值基础上的。这个搜索要么是整体的要么局限于一个父 TestObject 的子对象。

Rational Functional Tester 使用一个叫作 RootTestObject 的对象来代表正在被测试软件的整体视图。

  • 如果您想要搜索整个应用软件,您可以调用这个 RootTestObject 上的查明程序。
  • 如果您想要搜索一个特殊的对象,那么您可以简单地调用 TestObject 上的查明程序。搜索一个特殊的 TestObject 将仅仅搜索 TestObject 的子对象。

Mark Nowacki 和 Lisa Nodwell 编写了关于如何更好地理解并使用 TestObject.find 程序(参见 参考资源 中的第二个列表)。我已经向您们提供了我的代码样本这样您可以他们的代码。他们做了大量的工作通过实际的例子来解释和举例说明这些原则。

处理对象中不明确的识别

有时,Rational Functional Tester 在重新执行的过程中不能区别两个相似的对象。当同一个应用软件的两个浏览器或者图例同时打开时,通常会发生这样的情况。当两个 Web 浏览器都打开,Rational Functional Tester 将试图通过利用一个锚来确定这个目标对象,从而解决对象不明确的问题。既然您已经了解了如何使用查找程序,那么您可以通过利用一个 TestObject 参考来确定这个浏览器和应用软件实例。

在重新运行的过程中同时运行一个应用软件的多个实例,将会导致命令目标的模糊不清,比如 object() 或者 click()。要解决这个问题,当您调用 startApp 命令时可以使用 ProcessTestObject。在列表 2的实例中,ProcessTestObject 功能就像一个锚来确定您想要的应用软件的位置。

列表 2: 利用 ProcessTestObject 来确定这个应用软件的位置
ProcessTestObject pto1 = startApp("ApplicationOne");
ProcessTestObject pto2 = startApp("ApplicationTwo");
object(pto1, DEFAULT).click();

通过删除测试对象的注册表来清理内存

最后使用查找程序是删除这个对象的注册表。TestObject.find 会返回一个新的 TestObject 参考(有时称作 范围参考已查找参考,或者 非影射参考)。这些参考将保留对这个对象的访问权直到您明确地表明“没有注册”它们,这意味着如果您对它们使用不当将会导致一些错误。

Rational Functional Tester 不注册范围参考仅仅在整个重新运行结束以后,而不是当脚本结束时。只要这个对象的范围参考存在,Rational Functional Tester 就可能阻碍应用软件中对象的整个自由。例如,当您持有一个 Java™ 对象的范围参考,这个 Java 对象就不会看作是比较持久的需要,这样就会被删除。因此,一旦您不再需要它们时就明确地清除您所创建的任何范围参考的注册表是很好的方法。

RationalTestScript 包含几个您清除 TestObjects 参考的方法:

  • com.rational.test.ft.script
  • RationalTestScript.unregister
  • unregisterAll

警告:
当直接处理 TestObjects 时,利用它们可以在您的应用软件中引起不稳定性。要尽快清除您的 TestObjects 的注册表。

处理使用浏览器常见问题的方法

这里有几个您在测试 HTML 应用软件时可能遇到的几个常见问题,并说明了如何处理的方法。

利用 .readystate 方法选定令人惊恐的行为

如果您的浏览器或者浏览器中的对象状态不对,当您与它们发生相互影响时可以得到一些令人惊恐的(奇怪的,不稳定的)行为--尤其是当您不使用助手程序而产生了大量交互作用时。这就是为什么检查 Web 浏览器或者一个对象的 readyState 是良好习惯的原因。

Rational Functional Tester 中的 readyState 值
状态描述
0uninitializedObject对象未初始化数据
1loadingObject对象正在加载数据
2loadedObject对象已完成加载数据
3interactiveUser用户可以与对象交互,即时对象还没有被完全加载
4completeObject对象已被完全初始化

如果您知道您将要与一个大型表格/树(文件目录),或者 HTML 文档发生交互作用,那么在开始交互作用之前检查它们的状态(列表 3)是非常好的做法。

列表 3. 检查 readyState
  while 
  (Integer.parseInt(object.getProperty(".readyState").toString())
  < 4) 
  {
  sleep(2);
  }

通过利用 waitForExistence 程序来提高测试执行

您可能也注意到,在您重新运行您的测试脚本时,当这个重新运行窗口等待第一个命令运行时这个浏览器仍然在启动。这是因为新的浏览器速度很慢,或许是额外条目的原因,比如标签,现在需要加载。因此,当您打开一个浏览器时使用 waitForExistence 程序是很好的办法。这样做的方法之一是使用一个 Wait for Selected TestObject 验证点:

  1. 记录时,启用这个应用软件。
  2. 点击 Recording 工具条上的 Insert Verification Point or Action Command 按钮。
  3. Verification Point and Action WizardSelect an Object 页面上,点击 Object Finder 图表并拖到 HTML 页面 (而不是浏览器本身)。
  4. 点击 Next
  5. Verification Point and Action WizardSelect an Action 页面上,点击 Wait for Selected TestObject 选项。
  6. 如果需要,清除 Use the defaults 来更改 Maximum Wait Time Check Interval 设置,它们事先分别调整为2分钟和2秒。
  7. 点击 Finish

然而,您会发现在 startApp 命令之后添加这个调用程序会更简单。您所要做的只是参考 BrowserTestObject 并将这个调用程序添加到 waitForExistence 程序中。

处理意想不到的活动窗口

浏览器的另一个常见问题(和一些 Java 应用软件)是她众多意想不到的活动窗口。尤其当您的脚本在不同的机器上运行或者与不同的浏览器和浏览器配置一起运行时产生一些意想不到的活动窗口是十分常见的。

可是 Rational Functional Tester Help 文件提供了一对很好的解决方案(一个简易的,一个并不那么简单)。一种解决方案是使用标准的 try-and-catch (列表 4),等待消息的出现。如果没有出现,那么您可以继续。

列表 4. 等待一个活动对话框
  try 
  {
  // Dialog_HtmlDialogButtonOK().waitForExistence(5,1);
  Dialog_HtmlDialogButtonOK().click();
  }
  catch(ObjectNotFoundException e) 
  {
  }

提示:
如果您要等待一段精确数量的时间,您可以清除这个代码的注释行。

另一个有些棘手的解决方案,就是在一个 onObjectNotFound 特例中执行一个与此类似的检验。通过将这个执行置于助手的上标,您可以为任何能够扩展这个帮助器超类(此后会有更多)的 Rational Functional Tester 脚本的事件进行操纵。

考虑并不很常见的验证点

除了在记录过程中有详细说明的验证点之外,您还可以将新的验证点合并到 Rational Functional Tester 脚本中去(不仅仅可以使用 Insert at Cursor 命令)。脚本指南和动态验证点可以向您详细说明与 Test Object Map 中不存在的对象进行对比的具体数据。

手工验证点

当您自己创建一个验证点的数据并想将这个数据用来做比较时,手工验证点是十分有用的。例如,这个数据可能是一次计算的结果或者可能来源于外界,比如一个电子数据表,数据池,数据库,或者自定义的计算。

手工验证点是通过使用列表 5中的 vpManual 方法来构建的。

列表 5. 使用 vpManual 方法
  vpManual
  ("ManualVP_01", "Check something manually.").performTest();
  // or
  vpManual
  ("ManualVP_01", "Check something manually.", 
  "Check something manually.").performTest();

起初这个手工的验证点是有效的,如果这个验证点对象不存在,那么这个被传递的值将会变成基线值(稍后您可以在 Rational Functional Tester 中看到并对它进行编辑,正如任何其它验证点一样)。您的日志文件显示:创建验证点基线。

从这个点向前,对这个验证点任何后起的 vpManual 调用,都要将实际点与这个点做对比。如列表 5所示,您还可以通过传递基线和实际结果来调用 vpManual。在这种情况下,Rational Functional Tester 中的验证点将被忽视。

动态验证点

有些时候 ,您需要在您的对象图上没有的测试对象上执行验证点。要达到这一目的,您可以通过利用 vpDynamic 方法(列表 6)来使用动态验证点。在下一次这个脚本被重新运行时动态验证点就会激活适当的用户界面。您可以根据脚本详细指定的对象插入一个测试过的验证点。这样就避免了在记录这个验证点之前手工运行测试到适当的状态。

如果您只是传递了这个验证点的名称,那么 Recording Verification Point and Action 向导就会在下次脚本被重新运行时激活。利用这个向导,您就可以为以后测试对比的运行详细指定 TestObject 和数据。

列表 6. 使用 vpDynamic 方法
  vpDynamic
  ("DynamicVP_01").performTest();
  // or
  vpDynamic
  ("DynamicVP_01", TestObjectHere()).performTest();

警告:
列表 6中显示的第二个例子要求您传递实际的 TestObject。尽管这个具体的 TestObject 并不一定要来自 Test Object Map,但是它必须是与有意义的结果一致的同一个对象。此外,如果您使用的是查找方法 TestObjects,一定要仔细。

使用这些方法一个常见的问题是忽略了 performTest 方法。尽管这是允许的方法且在编译的时候没有任何警告,但是在脚本运行的时候没有任何引人注意的行为发生。

关于使用低级命令的详细资料

低级的回放仿效了用户执行的精确鼠标的动作和键盘的行为。这个回放还为特定的用户行为考虑了更多控制,比如绘制程序,PDA 仿真器,以及其它非传统的对象顺应工具,而不像简单的 点击输入 命令。

例如,假如您正在测试一个图 2中显示的 VTech Helio Emulator 中的手写识别。

图 2: VTech Helio Emulator
图 2: VTech Helio Emulator

传统的 Rational Functional Tester 脚本对于类似于 Helio Emulator 的应用软件无能为力。事实上,正如我在先前关于利用 IBM® Rational® Robot 的低级脚本的文章中所提到的(参见参考资源),关于您对类似于这样的应用软件设置的唯一选项是低级的记录。通过进入低级,您可以回放一个鼠标点击分解动作。

RootTestObject 类包括两个低级的方法:

  • emitLowLevelEvent(LowLevelEvent)
  • emitLowEvent(LowLevelEvent[])

制造商关于 LowLevelEvents 构建的 SubitemFactory 方法包括以下几种:

  • delay(int) 注意:按毫秒计
  • keyDown(string)
  • keyUp(string)
  • mouseMove(point)
  • mouseWheel(int)
  • leftMouseButtonDown()
  • leftMouseButtonUp()
  • rightMouseButtonDown()
  • rightMouseButtonUp()
  • middleMouseButtonDown()
  • middleMouseButtonUp()

列表 7中的脚本代码为 Microsoft® Paint® 中的 Helio 使用笔迹识别。

列表 7. 在 Rational Functional Tester 中使用低级的脚本
  afx10000008window().click(atPoint(100,100));
  LowLevelEvent llEvents[] = new LowLevelEvent[7];
  llEvents[0] = mouseMove(atPoint(100,100));
  llEvents[1] = leftMouseButtonDown();
  llEvents[2] = delay(250);
  llEvents[3] = mouseMove(atPoint(105,120));
  llEvents[4] = delay(250);
  llEvents[5] = mouseMove(atPoint(110,100));
  llEvents[6] = leftMouseButtonUp();
  getRootTestObject().emitLowLevelEvent(llEvents);

列表 7 中的代码在版面上产生一个字母 V,如图 3 所示。

图 3:在 Microsoft Paint 中使用 Helio Emulator
图 3:在 Microsoft Paint 中使用 Helio Emulator

这种巨大能力的缺点是什么呢?就我所知,不像 Rational Robot 一样,您需要手工编写所有的代码。我不清楚在 Rational Functional Tester 中启用一个低级记录器的方法。但是这样也好。如果您正在测试类似 Helio 的脚本,您无论如何要创建可重复使用的方法来编写字母。因此,大多数情况下,您需要一次就可以将它们描绘出来。

无论怎样,这是一个需要记住的很好的特性,因为在记录的时候您可能有几次并不能准确地获得 click-drag-type 组合。在那些情况下,有时低级的回放就可以得到答案。

怎样利用脚本帮助器超类加强您的脚本

如果您必须阅读 Dennis Schultz 编写的 "Creating a super helper class in IBM Rational Functional Tester," ,现在就开始进入 参考资源来进行。那篇文章是我见过的关于理解超类如何运行的最好的资源。助手类允许您将功能添加到您的测试脚本中。

默认情况下,所有的 Rational Functional Tester 脚本都会扩展 RationalTestScript 类,因此可以继承众多的方法(象 callScript)。高级测试者们可能更喜欢创建他们自己的帮助器超类来扩展 RationalTestScript ,并添加方法或者从 RationalTestScript 重写并覆盖这些方法。

无论何时您要在您的项目中创建或者记录一个脚本,您都可以详细指定 Rational Functional Tester 将使用的帮助器超类。这个默认的超类在功能测试的 项目属性 页面上有详细说明。您可以在功能测试的 脚本属性 页面详细说明单个脚本的帮助器超类。当创建完一个脚本以后,它保留着默认超类的参考,就好象是它自己的助手参考一样。

在多个脚本之间共享功能时,助手超类十分有用。一个超级助手将会为您提供一个独立的空间放置您想要每个脚本访问的代码。您放置的每个代码都会被扩展您的超级助手的助手类所继承。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Rational
ArticleID=272660
ArticleTitle=Rational Functional Tester 的高效测试自动化技巧
publish-date=11192007