IBM® Rational® Functional Tester 为测试人员提供了一个测试对象识别框架以及一个简单的用户界面,以执行基于 GUI 的测试脚本。但是,在有些条件下,例如测试一个基于 Eclipse 的程序,您可能会发现测试的 GUI 中全是二义性情形的测试对象。这些对象拥有几乎一样的属性,只有轻微的差异。很难直接指定目标对象属性的模式以及识别对象。识别的结果可能包含有多个二义性的类似对象,从而导致识别失败。本文向您介绍了怎样消除这些二义性的情况,并给出了一些指导以执行灵活且轻松的维护性测试脚本。
安装 IBM® Rational® Functional Tester V7 版本。
Rational Functional Tester 项目结构的概述
- 导入范例 Rational Functional Tester 项目(查看 下载)。您将会看到一个名为 BaseCase 的脚本以及一个名为 util 的文件夹。
- 通过选择 Window > Open Perspective > Java 来切换至 Java™ 视图。您将会看到以下的三个包:
- (default package)
- resources
- util
BaseCase 脚本位于默认的包中,其中还有它的辅助类 BaseCaseHelper ,以及与 Resources 包中脚本有关的其他配置文件。这两个包在 Functional Test 视图下看不到。您创建了 util 包,以及包中的类。在接下来的章节中,您将会使用到这个框架(见于图 1)。
图 1. Rational Functional Tester 项目的结构
建议您在 getMappedTestObject() 方法不能使用时,使用 find() 方法来找到一个测试对象。列表 1 中的代码显示了 find() 方法的结构。
// Finds all candidates that match given search criteria starting at this TestObject public TestObject[] find(Subitem properties); |
find() 方法通过将测试对象的特定属性,与给定的标准相比较以找到一系列的候选对象。您可以通过代表属性的名字/值,或者包含有一个或者多个匹配字符串来搜索一个测试对象。如果使用默认的 getMappedTestObject() 方法不能识别一个测试对象,那么您可以首先定位它的父类,然后通过访问父类的 find() 方法来找到目标测试对象。显然,find() 方法提供了可观的便利。脚本不再取决于对象映射。搜索候选测试对象的结果是可预测的,因此也是可靠的。您可以通过对象的属性值来找到一个测试对象,这些属性值可能是一个简单的文本。维护脚本起来会更加容易。
但是,如果 getMappedTestObject() 方法不可行的话,find() 方法不会包含所有的事例。不会总有明显系列的属性值会匹配。find() 方法取决于明显系列的属性值。因此,如果测试对象没有这样一系列的属性,那么这种方法就不会正常地发挥其功能。但是我们可以在返回的数组中一个个地试一下测试对象,这并不是一个聪明的办法。有时,甚至很难找到测试对象可识别的父类,所以搜索必须从最顶层开始,例如从窗口开始。这就会降低测试对象的可识别性。
考虑一下 find() 以及 getMappedTestObject() 方法的缺陷,您需要另外一个方法来解决 Rational Functional Tester 对象识别中的二义性情形。在本文中,我们介绍了基于路径导航方法,来找到目标测试对象。我们将会使用程序 ClassicsJavaA 作为一个范例。为了让事情变得更加简单,我们假设 Place Order 按钮就是要找的测试对象。
在记录 Place Order 按钮的点击操作之后,您会得到图 3 中对象映射的以下层级结构。您可以看到 Place Order 按钮是框架的子部分。框架会作为主窗口来显示,而且它就是 Place Order 按钮的位置所在。当然,在本例中,您可以简单使用 find() 方法来定位按钮。但是,我们将会尝试另外一种方法来解决这个问题。
有时测试人员会通过可见的线索来搜索测试的对象,例如关系中的相对位置。例如,您可能会通过它与文件夹封面图片的相对位置来找到 Place Order 按钮。与之类似,对于一个给定的测试对象,叫做锚对象,您可以使用 Rational Functional Tester API 来找到带有给定路径的任何对象。再次使用上面的例子,您可以通过找到对象附近的位置、文件夹的图片以及特定路径来找到 Place Order 按钮。这里所谓的术语“路径”是指在对象映射中将一个对象节点移动到另一个上时的逻辑距离。
在 Private Test Object Map for Script. BaseCase 窗口中,您知道 Place Order 按钮是主框架的子类。显然,该对象映射并 没有 包含主框架中所有的构件。按照以下步骤来得到对象映射树的大致轮廓:
- 点击 Test Object 然后在主窗口的菜单上点击 Insert Object(s) 以打开向导对话框。
- 使用 Object Finder 来强调主框架,然后选中它。
- 选择 Include all available objects on this window 然后点击 Finish 。
如图 4 所示,现在您可以看到添加至对象映射的主框架的更多子节点。
重点:
尽管您选择了“include all”选项,该选项并没有 包含主框架的所有子节点。该对象映射只能帮助您知道 Place Order 按钮的位置。
您可以使用另外一种工具,来找到主框架的所有子节点。实际上,您刚刚已经使用了它。它就是 Insert Object(s) 向导对话框(图 4)。使用这个向导,您就可以看到所有的 可映射对象。按照以下的步骤来定位 Place Order 按钮。
- 在主窗口中选择 Test Object >Insert Object(s) 以重新打开向导对话框(图 5)。
- 对于 Selection Method,选择 Test Object Browser 。
- 找到 Place Order 按钮,根据上面生成的测试对象映射给出的层级关系中的暗示进行操作。
根据 Test Object Browser,您可以在测试对象映射中看到许多的对象。对象浏览器中的对象的顺序,与测试对象映射中的顺序不同。但是,测试对象映射仅仅给了您一点暗示,以帮助您在对象浏览器中找到当前的对象。通过再一次按照前面介绍的步骤进行操作,您可以轻松找到文件夹的图形节点。然后您可以找到从图形节点到按钮节点的确切路径(见于图 6)。
如图 6 所示,从图形节点到按钮节点的路径如下所述。注意子类的索引在这里非常重要。
- 首先,将三个层次移动到父层次上。
- 然后移动主框架的 FIFTH 。
现在您已经知道,怎样找到两个测试对象之间的路径。在本部分中,您将会学到怎样使用 API 来自动定位带有给定路径的目标测试对象。这项任务所需的 API 在列表 2 进行了总结。
/** * This method returns an array of references to the object's mappable children. * The references to the objects should be released by calling he unregister method. * If the object has no mappable children, a 0-length array will be returned. **/ TestObject[] testObject.getMappableChildren(); /** * This method returns a reference to the parent object that appears in the object map. * The references to the objects should be released by calling he unregister method. **/ TestObject testObject.getMappableParent(); /** * This method returns the topmost mappable parent object that appears in the object map. * The references to the objects should be released by calling he unregister method. **/ TestObject testObject.getTopMappableParent(); |
至于简单性,我们并不使用 unregister 方法来注销迭代的测试对象。ObjectFinder 类是含有所有导航操作的辅助类。图 7 中的 UML 显示了这些类之间的关系。注意出于稳定性考虑,TestObjectNotLocatedException 必须源自于 RuntimeException 。
考虑一下路径范例,列表 3 向您展示了怎样书写代码以找到 Place Order 按钮:
// This method is used to find the button Place Order public GuiTestObject PlaceOrder() throws TestObjectNotLocatedException{ // The path we specified to find the button from the album image // First move up 3 times, then move down to the fifth child String pathString = "P3;C5"; Path path = null; try{ path = new Path(pathString); }catch(IllegalPathStringException illegalpath){ logError(illegalpath.getMessage()); } // Assume that the imageAlbum() is already found return new GuiTestObject(ObjectFinder.locateTestObject(imageAlbum(), path)); } |
首先我们指定一个路径字符串,它描述了从图标到 Place Order 按钮的路径。然后我们使用 ObjectFinder 类来定位我们想要的目标测试对象。
我们已经看到了,怎样以各种方法来找到一个测试对象。我们可以使用默认的方法来找到测试对象。我们还可以使用 find() 方法来找到匹配属性/值的测试对象。而且我们可以定位带有给定对象及路径的测试对象。在本段中,我们将会讨论怎样选择正确的方法,以及怎样组织 Rational Functional Tester 对象的源代码。
显然,默认的方法拥有丰厚的工具支持。Rational Functional Tester 提供了强大的工具,例如 Test Object Map 和 Script. Assure ,可以轻松解决脚本开发的复杂性问题,并降低开发所需的时间。但是,有一些脚本开发员所抱怨的正是简单性。他们认为工具隐藏了一些他们想要控制的细节。find() 方法是灵活和简单的。它使脚本开发员能够更强地控制测试脚本。这就是为什么在脚本开发中它得到广泛的应用,以替换默认方法的原因。基于导航对象识别方法非常有效和简单。有一点非常重要:它几乎可以在任何场所使用。但是,使用 UI 结构还是十分敏感的。
我们将会向您展示怎样使用 find() 方法,以及替代性的基于导航方法,同时享受使用工具所带来的便捷之处。
回忆一下 Rational Functional Tester 对象结构的第一部分。我们知道所有的对象搜索方法默认条件下都是在辅助类中执行。例如,搜索 Place Order 按钮的默认方法如列表 4 所示。
public abstract class BaseCaseHelper extends RationalTestScript. { /** * PlaceOrder: with default state. * .class : javax.swing.JButton * accessibleContext.accessibleName : Place Order * name : placeOrderButton2 * .classIndex : 0 */ protected GuiTestObject placeOrder() { return new GuiTestObject(getMappedTestObject("placeOrder")); } /** * Schubert4_14Jpg: with default state. * .class : javax.swing.JLabel * iconDescription : Schubert4_14.jpg * .classIndex : 2 */ protected GuiTestObject schubert4_14Jpg() { return new GuiTestObject( getMappedTestObject("schubert4_14Jpg")); } } |
然后您创建一个辅助类,该类扩展了默认的辅助类并超越了默认的方法。它如列表 5 中的代码所示。
public class BaseCaseUserHelper extends BaseCaseHelper { // This method is used to find the button Place Order public GuiTestObject PlaceOrder() throws TestObjectNotLocatedException{ // The path we specified to find the button from the album image // First move up 3 times, then move down to the fifth child String pathString = "P3;C5"; Path path = null; try{ path = new Path(pathString); }catch(IllegalPathStringException illegalpath){ logError(illegalpath.getMessage()); } // schubert4_14Jpg() is object for the cover image return new GuiTestObject( ObjectFinder.locateTestObject(schubert4_14Jpg(), path)); } } |
最后,让脚本类扩展用户定义的类。通过这种方法,您不需要编辑任何已存在的对象搜索方法。您只是超越了它们,将已存在的对象搜索方法的最强部分结合起来。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/14780873/viewspace-625557/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/14780873/viewspace-625557/