设为首页 收藏本站
查看: 1128|回复: 0

[经验分享] Using IBM Rational Functional Tester: Understanding and Using the TestObject.fin

[复制链接]

尚未签到

发表于 2015-10-3 12:57:26 | 显示全部楼层 |阅读模式
  Using IBM Rational Functional Tester: Understanding and Using the TestObject.find Method
  转载http://www.ibm.com/developerworks/rational/library/06/0711_nowacki_nodwell/
  使用 IBM Rational Functional Tester: 了解和使用 TestObject.find 方法
  转载http://www.ibm.com/developerworks/cn/rational/06/0711_nowacki_nodwell/
  Level: Intermediate     11 Jul 2006
  Mark Nowacki (mark_nowacki@us.ibm.com), Advisory Software Engineer, IBM Software Group, Lotus Software
Lisa Nodwell (lnodwell@us.ibm.com), Advisory Software Engineer, IBM Software Group, Lotus Software
  Mark Nowacki (mark_nowacki@us.ibm.com), 顾问软件工程师, IBM 软件集团, Lotus 软件
Lisa Nodwell (lnodwell@us.ibm.com), 顾问软件工程师, IBM 软件集团, Lotus 软件
  The TestObject.find method is a powerful part of Functional Tester that makes automated scripts easier to maintain. This introductorty article shows you easy ways to include TestObject.find in your automation framework.
  







TestObject.find 方法是 Functional Tester 的强大部分,可以使自动化的脚本更容易维护。本篇介绍性的文章向您展示了将 TestObject.find 引入到您的自动化框架中的简单方法。
  
  Part 1: Basics of the TestObject.find method
  The TestObject.find method is a Java™ method that the IBM® Rational® Functional Tester (RFT) tool uses to locate a TestObject in the application under test (AUT) dynamically, at runtime. By using it, you avoid having to record actions to add the TestObject to the Object Map.
  Mapped objects use stored, static, recognition properties and object hierarchies to verify that the script uses the correct control during playback. Although object recognition is quick with recorded objects, updating the properties can be time-consuming, especially when you need to change the property weight values or text properties of an object to regular expression (Regex) values. The find method gives you the option of eliminating most recorded controls from the Object Map.
  The TestObject.find method is more robust in the 6.X release of RFT. Performance is now nearly equal to that of using a mapped object.
  第 1 部分:TestObject.find 方法的基础
  TestObject.find 方法是一个 Java™ 方法,IBM® Rational® Functional Tester (RFT) 工具使用它在运行时,动态地在被测应用程序(application under test,AUT)中定位 TestObject。通过使用它,您可以避免不得不记录动作以向对象地图(对象地图(Object Map) ) 中添加 TestObject 对象。
  被映射的对象使用被存储的、静态的、识别属性和对象层次来验证,在回放过程中脚本使用了正确的控件。虽然使用被记录的对象进行对象识别速度很快,但是更新属性却是费时的,特别是当您需要将对象的属性权值,或者文本属性变更为正则表达式(regular expression,Regex)值时。find 方法向您提供一种能够排除大多数来自于对象地图(对象地图(Object Map) )的被记录控件的选项。
  TestObject.find 方法在 RFT 的 6.X 版本中更加健壮。现在,性能几乎与使用映射对象的性能相同。
  Benefits of using the find method
  One of the best reasons to use find instead of the Object Map is that you can easily change recognition properties of controls stored in Java or properties files. The advantage is that you do not have to change the recognition properties stored in an Object Map, so you avoid the more tedious and time-consuming way of using the Object Map UI to make the changes or rerecording the object to update it.
  使用 find 方法的好处
  使用 find 取代对象地图(对象地图(Object Map)) 的最好的原因中的一个是您可以很容易地变更存储在 Java 或属性文件中的控件识别属性。其优点是不必变更存储在对象地图(对象地图(Object Map))中的识别属性,这样您就避免了使用对象地图(对象地图(Object Map))UI 做变更,或重新记录对象来进行更新的更加冗长且费时的方法。
  Understanding and using find
  To understand the find method and its relationship to a mapped object, think about a control in your application that is likely to change, thus will require you to update an Object Map. The control may be something simple, such as an application that has a user-command button with a label that changes from release to release. For example, perhaps your AUT includes a dialog that involves a button labeled Open. In the previous release, that button was labeled OK. For the next release, the button will still be labeled Open, but there will also be a new button labeled Open with….
  If you recorded the OK button to the Object Map, you will need to change the recognition properties to accommodate the label changes, plus you will need to record the new Open with… button. (For this example, we are ignoring possible changes to the object hierarchy in the application that result from UI changes.)
  Next, assume that this dialog also mentions other buttons, such as Cancel and Help. You can see that the buttons can be differentiated by their labels, even if they appear in the application dialog in a different order in the future. Therefore, as long as you can differentiate between the buttons by the words on the labels, you do not have to be concerned about the index property or any other properties.
  了解及使用find
  要了解 find 方法以及它到映射对象的关系,考虑可能会改变的应用程序中的控件,因而您需要更新对象地图(对象地图(Object Map))。有些简单的控件方法,例如一个应用程序可能在版本更新过程中会变更其用户命令按钮的标签。例如,也许您的 AUT 中包含一个对话框,这个对话框中含有一个标签为Open的按钮。在以前的版本中,按钮的标签为OK。对于下一个版本,按钮的标签又变回了Open,但会有一个标签为Open with…的新按钮。
  如果您将 OK按钮记录到对象地图(对象地图(Object Map) ) 中了,那么您将需要变更识别属性来适应标签变更,并且您将需要记录新的 Open with… 按钮。(对于此实例,我们将忽略对由于 UI 变更导致的应用程序中的对象层次的可能的变更。)
  接下来,假设此对话框还包含了其他按钮,例如CancelHelp。您可以看到按钮可以用标签来区分,即使未来它们在应用程序中以不同的顺序出现。因此,只要您能够用标签上的文字来区分这些按钮,那么您就不需要考虑索引(index)属性或其他任意属性。
  Exploring find with ClassicsJavaA
  You can also use RFT to capture information about the controls that you may need to find later. For this illustration, use the ClassicsJavaA sample application provided with RFT and follow these steps.


  • Create a temporary Empty Functional Test script to hold your Object Map while you work on defining the properties of the buttons.
  • From the menu in the empty test scrip, select Script > Open Test Object Map.
  • Then select Applications > ClassicsJavaA to start the application.
  • Click the Place Order button.
  • Click the OK button in the Member Logon dialog.
  The Place an Order dialog should now be displayed. You can use this dialog to see how to use find to locate the buttons in the dialog and to get a TestObject for each control.
  
  利用 ClassicsJavaA 来探究 find方法
  您还可以使用 RFT 来获取关于随后您也许需要寻找的控件的信息。对于此例,使用RFT 提供的ClassicsJavaA 示例应用程序,并依照以下步骤。


  • 当您在定义按钮的属性时,创建一个临时的空的 Functional Test 脚本来保留对象地图(Object Map) 。
  • 在空测试脚本里的菜单中,选择Script > Open Test Object Map
  • 然后选择Applications > ClassicsJavaA 启动应用程序。
  • 单击 Place Order 按钮。
  • 单击 Member Logon 对话框中的 OK 按钮。
  现在应该出现 Place an Order 对话框。您可以使用该对话框来观察如何使用find 方法在对话框中定位按钮,以及为每个控件获得一个TestObject。
Figure 1. The Place an Order dialog from the ClassicsJavaA application
图 1. ClassicsJavaA 应用程序中的 Place an Order 对话框
DSC0000.jpg
  You’ll see three buttons in this next dialog: Related Items, Place Order, and Cancel. Look at the buttons as they appear in an Object Map, then proceed with these steps:


  • In the Private Test Object Map, select Test Object > Insert Object(s) from the menu.
  • Drag the Object Finder control over the Place an Order dialog, moving it to the title bar so that the entire dialog is surrounded by a red outline, then release the mouse button.
  • Now, from the Insert a GUI Object into the Object Map dialog, select Include all available objects on this window and click Finish.
  • Click the Place Order button.
  
  您将会在下一个对话框中看到三个按钮:Related Items、Place Order,和 Cancel。观察对象地图(Object Map)中出现的这三个按钮,然后继续以下步骤:


  • 在 Private Test Object Map 中,从菜单中选择Test Object > Insert Object(s)
  • 将 Object Finder 控件拖到 Place an Order 对话框上,将其挪到标题栏上,以使整个对话框四周包围着一个红色方框,然后释放鼠标按钮。
  • 现在,在 Insert a GUI Object into the Object Map 对话框中,选择 Include all available objects on this window 并单击Finish
  • 单击 Place Order 按钮。
  You should now have a javax.swing.JFrame object in your Object Map. Select the JFrame control so that you can look at the Recognition properties for the dialog. For this control, the label, or text, is the most significant of two attributes that define the control. The second important attribute is the class of the control, because there may be many JFrame objects displayed, but probably only one labeled Place an Order. Continue with these steps:
  您现在的对象地图(Object Map)中应该有一个 javax.swing.JFrame 对象。选择 JFrame 控件,以便您可以看到对话框的 Recognition 属性。对于此控件,标签或文本是定义该控件的最重要的两个属性。第二重要的属性是控件的类,因为可能会显示出许多 JFrame 对象,但是可能只有一个的标签为 Place an Order。继续以下步骤:


  • Expand the hierarchy to find the button labels.展卡层次结构,找到按钮标签。
  • Select the Cancel button so that you can examine the Recognition properties that RFT uses to describe the button in the Object Map. There are four properties listed, two of which are crucial to defining the correct button: the class and the accessibleContext.accessibleName properties (see Figure 2.)
    选择 Cancel 按钮,以便您可以分析 RFT 用来在对象地图(Object Map)中描述按钮的 Recognition 属性。这里列出了四个属性,其中两个对定义正确的按钮是至关重要的:class 和 accessibleContext.accessibleName 属性(参见图 2)。
  Figure 2. Example of an Object Map using the ClassicsJavaA application使用 ClassicsJavaA 应用程序的对象地图(Object Map)的实例
DSC0001.jpg



  • Find the correct button. Many dialogs include a Cancel button, so you first need to find the dialog TestObject that contains the correct Cancel button. If you find the correct dialog first, it is easier to find the correct button within that dialog.
  • Go back to your empty test script. Because the dialog is a high-level object, you can start your TestObject search by defining the RootTestObject. After you have done that, you can use the find method to locate the dialog TestObject:
  RootTestObject root = getRootTestObject();
  You are ready to use the find method to locate the Place an Order dialog, using the class information for the window.


  • 找到正确的按钮。许多对话框中包含一个 Cancel 按钮,所以您首先需要找到包含正确的 Cancel 按钮的对话框 TestObject。如果您首先找到了正确的对话框,那么找到对话框中正确的按钮就更容易了。
  • 回到您的空测试脚本中。因为对话框是高级对象,所以您可以通过定义 RootTestObject 来开始 TestObject 搜索。当您做完这些后,您就可以使用 find 方法来定位对话框 TestObject:
  RootTestObject root = getRootTestObject();
  您已准备好使用 find 方法来定位 Place an Order 对话框,利用窗口的类信息。
  Note: Be sure to print the properties of all TestObjects you find, so you can review them.
  Your commands should look something like this:
  注意:确保打印出您找到的所有 TestObject 的属性,这样您可以检查它们。
您的命令应类似以下内容:
  

// get all test objects of type JFrame (dialog)
TestObject[] to = root.
find(atDescendant("class", "javax.swing.JFrame"));
// print dialog test object properties to console
for (int i = 0; i < to.length; i++)
{
System.out.println (to.getProperties());
}



  The resulting screen output should look something like this (minus most of the properties, to save space):
  结果显示应该类似以下内容(除去了大部分属性,为了节省空间):
  

{height=600, displayable=true, undecorated=false, ...,
class=javax.swing.JFrame, title=Place an Order, &#8230;}



  Next, instead of the above code, use the find method to locate the Place an Order dialog by using the label text for that window in the dialog:
  接下来,使用 find 方法代替上面的代码,利用对话框中该窗口的标签文本来定位 Place an Order 对话框:
  

// get all test objects that have the title "Place an Order"
TestObject[] to = root.
find(atDescendant("title", "Place an Order"));
// print test object properties to console
for (int i = 0; i < to.length; i++)
{
System.out.println(to.getProperties());
}



  In both cases, you will find only one object and the properties displayed will be the same. That is the ideal situation. To increase the likelihood of that result in every situation, you can combine the two properties into one find call:
  在两种情况下,您会发现只有一个对象和被显示的属性是相同的。这是理想的情况。要提高每种情况下该结果的可能性,您可以将两个属性组合成一个 find 调用:
  

// get all test objects of type JFrame (dialog)
// AND have the caption "Place an Order"
TestObject[] to = root.
find(atDescendant(("class", "javax.swing.JFrame",
"title", "Place an Order"));



  Now that you have found the control that contains the button with the label that you were searching for, you can use find to locate the correct button:
  既然您已经找到了包含带有您搜索的标签的按钮的控件,那么您就可以使用 find 来定位正确的按钮了:
  

// capture the correct dialog as a test object
TestObject toPlaceAnOrderDialog = to[0];
// reuse the test object array, finding all buttons on the
//   "Place an Order" dialog that have the caption "Cancel"
to = toPlaceAnOrderDialog.
find(atDescendant("class", "javax.swing.JButton",
"text", "Cancel"));
// verify that only one button was found
System.out.println(to.length);
// capture the correct button as a GuiTestObject
GuiTestObject cancelButton = new GuiTestObject(to[0]);



  You can call find from any TestObject. Depending on the object you select, the search is restricted to objects in the hierarchy below the one you select.
  In the example above, the code uses atDescendant to locate the button. However, there are several methods that you can use with find:


  • atChild searches for any direct child of the TestObject.
  • atDescendant looks for any child of the TestObject.
  • atList lets you specify a list of atChild, atDescendant, and atProperty objects, so you can narrow the search.
  
  您可以从任何 TestObject 来调用 find方法。这依赖于您所选的对象,搜索只限于您所选择的对象下面层级的对象。
  在上面的实例中,代码使用 atDescendant 来定位按钮。然而,您可以有许多方式来使用 find:


  • atChild 搜索 TestObject 所有直接的子对象。
  • atDescendant 寻找 TestObject 的所有子对象。
  • atList 让您指定一个 atChild、atDescendant,和 atProperty 对象的列表,这样您可以减小搜索范围。
  Part 2: Examples of practical applications of the TestObject.find Method
  Experimenting with various properties will help you determine which properties will work best for finding objects in your application. As soon as you understand how find helps you define your controls dynamically, you can begin to write getter methods, so you can locate objects without relying on a recorded Object Map.
  第 2 部分:使用 TestObject.find 方法的实际应用程序的实例
试验各种属性将帮助您确定哪个属性在寻找应用程序中的对象时工作的最好。您一旦了解了 find 方法如何帮助您动态定义控件,您就可以开始编写 getter 方法了,这样您就可以不依赖被记录的对象地图(Object Map)来定位对象了。
  Defining Controls As Part of the Dialog
  For the Place an Order dialog, for instance, you might decide to define the controls as part of the dialog. In that case, you would first find the dialog, then look inside the dialog for the control you want to modify. For that scenario, your code design might look like this:
  将控件定义为对话框的一部分
  例如,对于 Place an Order 对话框,您可能决定将控件定义为对话框的一部分。在这种情况下,您应首先找到该对话框,然后,到对话框中找您希望修改的控件。对于该情境,您的代码设计应该如下所示:
  

            public class PlaceAnOrder
{
public static GuiTestObject getDialog()
{
RootTestObject root = getRootTestObject();
TestObject[] to = root.
find(atDescendant("title", "Place an Order"));
return new GuiTestObject (to[0]);
}
public static GuiTestObject getButtonCancel()
{
TestObject[] to = getDialog()
.find(atDescendant("class", "javax.swing.JButton",
"text", "Cancel"));
return new GuiTestObject(to[0]);
}
}



  Here is an example of how you might use these methods in a script:
  这里是一个说明如何在脚本中使用这些方法的实例:
  

public void testMain(Object[] args)
{
// Find the Place an Order dialog
GuiTestObject dialogPlaceAnOrder = PlaceAnOrder.getDialog();
GuiTestObject cancelOrder = PlaceAnOrder.getButtonCancel();
cancelOrder.click ();
}



  Defining Methods for Finding Common Objects
  To find more common button labels, such as Cancel, you may need to develop more general methods that find any button that exists in your application. For example, you might use getButton("Cancel", placeAnOrderDialog), where parent is the parent window. For this second scenario, your design would look something like this example:
  为找到通用的对象定义方法
  要找到更多通用的按钮标签,例如,Cancel,您可能需要开发更多能够找到存在于您的应用程序中的任意按钮的通用方法。例如,您可以使用getButton("Cancel", placeAnOrderDialog),在此,来源是父窗口。对于第二个情景,您的设计应该类似于此实例:
  

public class ClassicsJavaUI
{
public static GuiTestObject getButton(String buttonName,
TestObject parent)
{
TestObject[] to = parent.find(SubitemFactory.atDescendant
("class", "javax.swing.JButton", "text", buttonName));
return(new GuiTestObject(to[0]));
}
public static GuiTestObject getButton(String buttonName)
{
RootTestObject root = RationalTestScript.getRootTestObject();
TestObject[] to = root.find(SubitemFactory.atDescendant
("class", "avax.swing.JButton", "text", buttonName));
return (new GuiTestObject(to[0]));
}
public static GuiTestObject getDialog(String dialogName)
{
RootTestObject root = RationalTestScript.getRootTestObject();
TestObject[] to = root.find(SubitemFactory.atDescendant
("class", "javax.swing.JFrame", "title", dialogName));
System.out.println (to.length);
return (new GuiTestObject (to[0]));
}
}
public class PlaceOrderWindow
{
public static GuiTestObject getDialog()
{
return ClassicsJavaUI.getDialog("Place an Order");
}
public static GuiTestObject getButtonPlaceOrder()
{
return ClassicsJavaUI.getButton("Place an Order", getDialog());
}
}



  Here is an example of how you might use these methods in a script or, more appropriately, with a class that defines the Place An Order dialog:
  这里是一个您可以如何在脚本中使用这些方法的实例,或者更适当地说,利用定义了 Place An Order 对话框的类:
  

public void testMain(Object[] args)
{
GuiTestObject dialog = PlaceOrderWindow.getDialog();
GuiTestObject buttonPlaceOrder =
PlaceOrderWindow.getButtonPlaceOrder();
buttonPlaceOrder.click ();
}



  The application you are testing will determine how you define your methods for finding the controls. The following section is an actual example of how a system was designed around the find method.
  您测试的应用程序将确定您为寻找控件如何定义方法。下面部分是一个实际的例子,说明了系统是如何围绕 find 方法而设计的。
  Actual Use of the RFT find in an Eclipse-based Application
  This example of using the find method in testing the application based on Eclipse was limited to only a part of the AUT as a way to work out the design of the object getter methods. There is a discernable pattern with objects in this application. Standard SWT objects were predominant, but there are some special, custom classes provided by the application development team.
  Test developers created generic methods to get all objects of a particular class or to get just one object at a given index under a specific parent object. To allow the automation to work on localized versions of the application, the test developers decided to use object indices as the key property for finding objects, rather than text. The classes described below are designed to do this.
  在基于 Eclipse 的应用程序中实际使用 RFT find 方法
  在测试基于 Eclipse 的应用程序中使用 find 方法的这个实例仅局限于 AUT 的一个部分,作为得出对象 getter 方法的设计的一个途径。本应用程序中的对象具有可识别的模式。标准的 SWT 对象是主要被使用的,但还有应用程序开发团队提供的一些专门的定制类。
  测试开发人员创建一个通用的方法来获取一个特定类的所有对象,或者获取一个具体父对象下给定索引号的一个对象。要使得自动化在应用程序的局部版本上工作,测试开发人员决定使用对象索引作为寻找对象的关键属性,而不是文本。下面介绍的类将用于做这件事。
  Note: All methods in these classes are static, so the test developer does not need to instantiate an object of this type to use them. They can be called by using the format <class name>. <method name> (<parameters>).
  The FindAppObjects.java class enables you to use two different methods: getAllObjects and getObjectAtIndex . These methods are not usually meant to be used directly, but they are the basis for other methods. However, you can use them directly to determine which objects are found in which indices.
  注意:这些类中的所有方法都是静态的,所以测试开发人员不需要将这个类实例化为一个对象就可以使用这些方法。可以通过使用以下格式来调用它们:<class name>. <method name> (<parameters>)。
  FindAppObjects.java 类可以让您使用两个不同的方法:getAllObjects 和 getObjectAtIndex 。这些方法通常不直接使用,但它们是其他方法的基础。然而,您可以直接使用它们来确定通过哪些索引号找到哪些对象。
  

            /**
* Given a parent object, find all descendant test objects with a
* given class.
* @param parent TestObject
* @param className String
* @return Array of TestObject or null if no objects of type
*  className were found.
*/
public static TestObject[] getAllObjects(TestObject parent,
String className)



  getAllObjects takes a parent TestObject and a class-type string as input, and then returns an array of TestObjects that include all descendents of the parent object that are of the specified class type. This example returns all child dialogs of the RootTestObject:
  getAllObjects 将 TestObject 类型的父对象和 String 类型的字符串为输入,并返回包含了父对象的具体类型的所有子对象的 TestObject 的数组。此实例返回 RootTestObject 的所有子对话框:
  

RootTestObject root = getRootTestObject ();
TestObject[] dialogs =
FindAppObjects.getAllObjects(root, "javax.swing.JFrame");



  Selecting the correct parent TestObject is important, so that you get only the objects that you are looking for among the results. As an example, suppose that the following represents an object hierarchy in the AUT:
  选择正确的父 TestObject 对象是重要的,以便您可以从结果中只获得您正在寻找的对象。作为一个实例,假设下面的部分表示 AUT 中的一个对象层次:
  

application
composite
group0
button0
button1
group1
button0
button1



  Calling getAllObjects (application, "button") will return an array of four buttons. However, you cannot quickly determine which indices match which buttons without looping through the array and printing each index and the button[index].getProperty("text") string.
  Instead of that cumbersome process, it makes more sense to do more than one hierarchical call:
  Calling getAllObjects (application, "button") 将返回一个含有四个按钮的数组。然而,如果不循环扫描该数组,并打印出每个索引号和 button[index].getProperty("text") 字符串的话,就不能很快确定哪些索引号匹配哪些按钮。
  要取代这种麻烦的过程,进行一个以上的分层调用更有意义:
  

// get all groups in the application
TestObject[] groups = FindAppObjects.getAllObjects
(application, "group");
// limit search to only buttons in the first group found
TestObject[] buttons = FindAppObjects.getAllObjects
(groups[0], "button");
// click the first button found under the group
new Button(to[0]).click();



  The getAllObjects (group0, "button") call returns only two buttons, and they are likely to be in the correct order (button0, then button1), as displayed on the screen. If there are only a few buttons in the entire application or dialog, it may be easier just to get all buttons and figure out the indices.
  getAllObjects (group0, "button") 调用只返回两个按钮,它们很可能处于正确的顺序(button0,然后 button1),如屏幕上显示的。如果整个应用程序或对话框中只有一些按钮,那么获得所有的按钮并且计算出索引可能会更容易。
  

/**
* Given a parent object, find the descendent test object
* with a given class, at a given one-based index.
*
* @param parent TestObject
* @param className String
* @param index int, zero-based index
* @return TestObject or null if index is greater than
* the total number of objects found.
*/
public static TestObject getObjectAtIndex
(TestObject parent, String className, int index)



  getObjectAtIndex refines the use of getAllObjects. It takes a parent TestObject, a class-type string, and a zero-based index integer, and then returns a single TestObject. This code, for example, returns the first button found below the given (parent) group:
  getObjectAtIndex 精炼了 getAllObjects 的使用。它获取一个父的 TestObject 对象、一个 String 类的字符串对象,和一个以零为基数的整数,然后返回一个单个的 TestObject 对象。例如,此代码返回指定(父)分组下的第一个按钮:
  

            TestObject to = getObjectAtIndex(group1, BUTTON, 0);



  These methods return TestObjects, and those may not be the specific type of object you need to find. The above methods both return generic TestObjects. Many times, you will want to use a specific type of object instead. When using these methods, be sure to explicitly cast the returned TestObject(s) to the correct type of object before using in your code.
  The FindBasicAppObjects.java class provides further refinement and assistance. It is a subclass of FindAppObjects.java, and uses the getObjectAtIndex method. It contains getter methods that return the child object of type class at index from TestObject parent. This was already cast as the correct class of product object, so you do not need to cast it yourself. This example returns a subset of the standard Eclipse SWT widget types, such as org.eclipse.swt.widgets.Button:
  这些方法都返回一个 TestObject 对象,并且那些可能不是您需要找的具体类型的对象。上面的两个方法都返回一般的 TestObject 对象。常常,您希望使用具体类型的对象。当使用这些方法时,确保在您将对象用于代码中之前,显式地将所返回的 TestObject 对象转换为正确的类型。
  FindBasicAppObjects.java 类提供进一步的细化和辅助。它是 FindAppObjects.java 的子类,并且使用了 getObjectAtIndex 方法。它包含返回 TestObject 父对象的索引号位置的子对象的 getter 方法。这时产品对象已经被转换成为了正确的类,所以您不需要自己再次的转换它。此实例返回标准的 Eclipse SWT widget 类的一个子集,例如 org.eclipse.swt.widgets.Button:
  

            /**
* Find the index-specified org.eclipse.swt.widgets.Button
* child control under the specified parent.
*
* @param parent TestObject
* @param index int, zero-based
* @return WButton
*/
public static WButton getButton(TestObject parent, int index)



  getDialog is the only method in FindBasicAppObjects.java that does not take a parent, because it assumes that the parent is the AUT. To be able to recognize the correct dialog even if the dialog has a mutable caption, getDialog takes a regular expression (Regex) object as a parameter, as this shows:
  getDialog 是 FindBasicAppObjects.java 中唯一一个不需要父亲对象的方法,因为它假设父对象是 AUT。为了能够识别正确的对话框,即使该对话框的标题是易变的,getDialog 将正则表达式(Regex)对象作为参数,如下所示:
  

            /**
* Find a org.eclipse.swt.widgets.Shell control
* with a caption specified by the given
* Regular Expression (Regex).
*
* @param dialogCaption Regex object containing dialog's
*        expected caption
* @return WFrame
*/
public static WFrame getDialog (Regex dialogCaption)



  Compare the code for the Place an Order dialog (at the beginning of this section) with the same behavior using FindAppObjects and FindBasicAppObjects in the following example. It assumes that the Place an Order dialog is an Eclipse dialog of type WFrame and that the buttons are of type WButton.
  比较 Place an Order 对话框的代码(在此部分的开头)和在下面实例中使用FindAppObjects 和 FindBasicAppObjects 的同样的行为。假设 Place an Order 对话框是 WFrame 类型的 Eclipse 对话框,并且按钮是 WButton 类型的。
  

            public class PlaceAnOrder extends RationalTestScript
{
private final int CANCEL = 2;
private final Regex DIALOG_CAPTION = new Regex
("^Place an Order$");
public WFrame getDialog()
{
return FindBasicAppObjects.getDialog(DIALOG_CAPTION);
}
public WButton getButtonCancel()
{
return FindBasicAppObjects.getButton(getDialog(),CANCEL);
}
public void testMain(Object[] args)
{
getButtonCancel().click();
}
}



  The preceding code is written in a way that&#8217;s easy to maintain, with each part of the code segregated into understandable chunks. For coders who prefer a more compact layout, that code could be rewritten this way:
  前面的代码是以很容易维护的方式编写的,代码中每个部分都分隔为容易理解的一块。对于喜欢更加紧凑布局的编码人员,该代码还可以以此方式书写:
  

            public class PlaceAnOrder extends RationalTestScript
{
public void testMain(Object[] args)
{
FindBasicAppObjects.
getButton (FindBasicAppObjects.
getDialog (DIALOG_CAPTION), CANCEL).click();
}
}



  Always Write Unit Tests
  In addition to the find-based getter methods, the FindBasicAppObjects.java class mentioned previously includes rudimentary unit test methods for each of the defined object types. Each of these unit test methods takes an object of a specific class and a string (where the string is expected to be the name of the getter method that you are testing). This name is sent to the console to track pass-or-fail results.
  The unit test methods first verify that the object provided is not null, and then perform one or more very basic actions on the object. For example, the unit test method for a WButton object prints the text property (label) for the object. You can then see whether the getter method is returning the correct button.
  Using unit test methods to test every getter method is recommended. Unit testing is often regarded as extra work, but after any change to the application&#8217;s user interface (UI), running the unit tests will verify that the methods continue to find the correct controls in the AUT and will confirm that any code changes in the getter methods are working correctly. Running unit tests assures that test case code will continue to find and return the correct objects.
  总是编写单元测试
  除了基于 find的 getter 方法以外,前面提到的 FindBasicAppObjects.java 类还包含每个已定义的对象类型的基本的单元测试方法。每个单元测试方法获取一个具体类的对象和一个字符串(字符串应该是您在测试的 getter 方法的名称)。该名称被发送到控制台,以跟踪通过或是失败的结果。
  单元测试方法首先验证所提供的对象不是空的,然后对该对象执行一个或多个非常基础的操作。例如,WButton 对象的单元测试方法打印出该对象的文本属性(标签)。您可以看到 getter 方法是否返回正确的按钮。
  推荐使用单元测试方法来测试每个 getter 方法。单元测试常常被视为多余的工作,但在对应用程序的用户界面(UI)做任何变更之后,运行单元测试将验证方法能继续找到 AUT 中正确的控件,并将确认 getter 方法中的任何代码变更能正确工作。运行单元测试确保测试用例能继续找到并返回正确的对象。
  

      /**
* Unit test for button controls.
*
* @param b
* @param methodName Name of method under test
*/
public static void verifyButton(WButton b, String methodName)



  Example of calling a unit test method: 调用单元测试方法的实例:
  

      FindBasicAppObjects.
verifyButton(getButtonCancel(),"getButtonCancel");



  Limitations and Recommendations
  Always find the control before you use it; never depend on TestObjects saved in your code. The object you find may change (or be deleted and recreated) between the first time you find the object and the next time you need to use it. Be sure you have the correct object by calling find each time you work with the object.
  You cannot record scripts if you are using find. Because your TestObjects are not defined in the Object Map, the recorder will not pick up the correct object name while recording. You can still use recording for basic structural code that you need for your scripts, but you will need to substitute your find-based getter methods for the mapped-control getters that are recorded.
  Many objects may appear to be the same. There may be more than one OK button in existence when you call the find method. Make sure that you have the correct button by using a distinguishing property, such as the dialog that the OK button is in. Print the result of the getProperties method on the TestObject to the console to see which properties can help you differentiate the object you seek from similar objects.
  
  局限性和建议
  总是在使用控件之间找到它,不要依赖于代码中存储的 TestObject。您找到的对象可能在您第一次找到它时和您下次需要使用它时之间变更了(或者删除并重新生成了)。每次您处理一个对象时,都需要调用find 方法来确保您得到正确的对象。
  如果您使用 find 方法,您不能记录脚本。因为您的 TestObject 不是在对象地图(Object Map)中定义的,在记录中,记录器不能挑出正确的对象名称。您仍旧可以对您的脚本所需的基本结构代码进行记录,但您需要用基于 find 的 getter 方法来取代所记录的被映射控件的 getter 方法。
  许多对象可能会显示出一样的结果。当您调用 find 方法时,可能会存在一个以上的 OK 按钮。确保通过使用不同的属性,例如 OK 按钮所属于的对话框,来获得正确的按钮。。将 TestObject 的 getProperties 方法的结果打印到控制台上,以观察哪个属性可以帮助您在类似的对象中区分出您所找的对象。
  Resources参考资料
  Learn



  • Advanced XDE Tester Topics: Leveraging the power of regular expressions Platform (IBM developerWorks, March 2004) describes ways to use regular expressions, using ClassicsJavaA as the sample application.
  • Framework Automation with IBM Rational Functional Tester: Modularity (IBM developerWorks, October 2005) shows examples of how to break your automation into more manageable segments.
  • Understanding TestObjects in Rational Functional Tester is an IBM Technote that explains the relationship between a TestObject and the test application.
  • Rational Functional Tester Help. See TestObject subsection on the find method for subitem properties for help on the different ways to use find.
  • Learn more, visit the Functional Tester product resource area on developerWorks Rational. You'll find technical documentation, how-to articles, education, downloads, product information, and more.
  学习




    • 您可以参阅本文在 developerWorks 全球网站上的 英文原文。
    • Advanced XDE Tester Topics: Leveraging the power of regular expressions Platform(IBM developerWorks,2004 年 3 月)介绍了使用正则表达式的方法,其中利用 ClassicsJavaA 作为示例应用程序。
    • Framework Automation with IBM Rational Functional Tester: Modularity (IBM developerWorks,2005 年 10 月)介绍了如何将自动化部分分为更加易管理的片断的实例。
    • Understanding TestObjects in Rational Functional Tester 是一篇 IBM 技术手记,它阐述了 TestObject 和测试应用程序之间的关系。
    • Rational Functional Tester 帮助。参见 find 方法子项目属性中的 TestObject 子部分,以得到使用 find 的不同方法的帮助。
    • 要了解更多内容,请访问 developerWorks 中国网站 Rational 专区上的Functional Tester 产品资源专区。您将会找到技术文档、教程、培训、下载、产品信息等等。

  
Get products and technologies



  • A trial copy of Rational Functional Tester from the IBM Rational web site.
  获得产品和技术
IBM Rational 网站上的Rational Functional Tester 的试用版本。
  Discuss



  • Advanced IBM Rational XDE Tester topics: working with the Object Map (IBM developerWorks, June 2004) explains how to handle situations when scripts have trouble recognizing objects and how to make controls in the Object Map more robust.
  • In the Functional and GUI Testing discussion forum and get involved in the developerWorks community.
  讨论



  • Advanced IBM Rational XDE Tester topics: working with the Object Map (IBM developerWorks,2004 年 6 月)阐述了如何处理脚本遇到对象识别的问题时的情况,以及使对象地图(Object Map)中的控件更加健壮。
  • 参与 Functional 和 GUI Testing 论坛(英文)并加入 developerWorks 社区。
  About the authors
  Mark Nowacki has worked with test automation tools for 15 years. He is the overall IBM Workplace Managed Client (WMC) GUI Automation Coordinator, as well as automation team lead for the WMC Messaging, Instant Contacts, and Activity Explorer test team.
  Lisa Nodwell has been working with software automation tools for 16 years. She has extensive experience with large test automation projects using Segue SilkTest and, currently, with IBM Rational Functional Tester.

  作者简介
  Mark Nowacki 已经致力于测试自动化工具 15 年了。他是整个的 IBM Workplace Managed Client (WMC) GUI Automation Coordinator,以及 WMC Messaging、Instant Contacts,和 Activity Explorer 测试团队的自动化团队负责人。
  Lisa Nodwell 已经致力于软件自动化工具 16 年了。她拥有丰富的使用 Segue SilkTest 进行大型测试自动化项目的经验,目前她致力于 IBM Rational Functional Tester 的工作。
  

  
  
  



Understanding TestObjects in Rational Functional Tester

Problem(Abstract)
  This technote discusses the significance of TestObjects in IBM&#174; Rational&#174; Functional Tester (RFT), and strategies for avoiding problems when the user programmatically references TestObjects.
  Resolving the problem[/td]
[/tr]
[tr]
[td=1,1,443]A TestObject in represents a connection point between the script that is playing back and the Software Under Test (SUT). There is a corresponding object that exists in the SUT for the TestObject that exists in the RFT script.
In the normal course of action statements are recorded and objects are added to the Object Map. The Object Map contains information that the script can then use to construct and find a TestObject. When something like Button().click() is recorded the Button() method finds an object based on mapped properties and then &#8220;binds&#8221; the TestObject to an object in the SUT. This binding is necessary to query information from the actual object, i.e. asking the button directly where it is currently on the screen. The click() is then executed and the TestObject is unregistered, releasing the connection to the actual object in the SUT. When using TestObjects from the map in this fashion the lifetime of the object is automatically managed.
  When the TestObject is registered, the object in the SUT cannot be freed. In fact, the object in the SUT remains bound until playback ends (not just the containing script but the entire playback) or is unbound using an explicit call to unregister(). This is the same as the unregister which happens automatically when using objects found from the map. This means that if the TestObject is not unregistered and the SUT is a Java application, the underlying object in the SUT is not garbage collected. If the TestObject is not unregistered and the SUT is a web application, the COM object representing the HTML element is not de-referenced.
  This is particularly important for HTML testing, which is inherently state-based. HTML documents and elements frequently change as user actions are performed (such as clicking a link). It is therefore dangerous to keep references to objects of past web pages alive in the browser since the browser itself is not necessarily designed with that thought in mind. Bound TestObjects that RFT does not automatically manage must be used with extreme care and attention to ensure that they are unregistered as soon as they are no longer needed. Conversely, TestObjects that are unregistered (no longer bound) should not be used.
  By default, RFT does not record any actions that involve TestObjects that are not automatically unregistered by RFT. This removes the important responsibility on the tester&#8217;s part to manage object lifetime. However, a tester can easily get a bound TestObject programmatically, that is, through scripting by using the RFT API.
  APIs that directly return bound TestObjects include:


  • getChildren
  • getMappableChildren
  • getParent
  • getMappableParent
  • getTopParent
  • getOwner
  • getOwned
  • find
  There are some guidelines to keep in mind when using API involving TestObjects. First and foremost is to conscientiously unregister all TestObjects when they are no longer needed. The normal sequence of events would be to obtain a TestObject, query some properties for verification or test, and then immediately unregister the object. When writing this code you must accurately envision the flow of the code under all conditions. Could an exception be thrown causing unregistration to be skipped? Could a method return after finding a desired result and subsequently not execute the unregister code? These types of questions must be asked when developing complex script dealing with TestObjects.
  What follows are some examples of useful patterns that can be applied to scripts to ensure that proper object lifetime is maintained.
  Use Try/Finally to ensure that unregister is called if an exception is thrown:

  

TestObject to = MyObject().getParent();
try  {
  // Do relevant stuff with the TestObject
  to.getProperty(&#8220;prop&#8221;);
  }
  finally
  {
  // This ensures that the TestObject is unregistered even
  // if an exception is thrown (such as PropertyNotFound),
  // while still allowing the exception to percolate
  //(not be caught).
  to.unregister();
  }




  
Extracting one desired result from an array:

  

// This searches the children to match a certain criteria
TestObject[] children = MyObject().getChildren();  TestObject found = null;
  try
  {
  for (int i=0; i<children.length; i++)
  {
  if (children.getProperty(&#8220;prop&#8221;).equals(goodProp))
  {
  // Keep track of the desired object
  found = children;
  
  // nulling out children ensures that the
  // desired object is not unregistered when then array
  // is unregistered in the finally block.
  children = null;
  break;
  }//end of if block
  }//end of for loop
  }//end of try block
  finally
  {
  // a convenience method exists on RationalTestScript to
  // unregister arrays of TestObjects.
  unregister(children);
  }//end of finally block




  
Use the find() API instead of a recursive child search:
  A common task is to do a recursive search of children of an object to look for a descendant that matches a given set of properties. These algorithms can be quite complex and error prone.
  Using find() via a TestObject or the RootTestObject can do this instead. The find() API is new functionality that has been added to RFT.
  Using find()


  • Eliminates the need to manage the lifetime of uninteresting objects
  • Dramatically speeds up script execution
  • Makes scripts easier to understand and maintain  



    TestObject[] found = MyObject().find(atDescendant(
    atProperty(&#8220;.class&#8221;, &#8220;Button&#8221;),  atProperty(&#8220;.name&#8221;, &#8220;OK&#8221;)));
      // Now all the &#8220;OK&#8221; buttons that are children of MyObject
      // have been found.
      // Be sure to unregister the results when finished using the
      // TestObjects in the found array.
      Unregister(found);



  In addition to the aforementioned API that returns objects in the SUT GUI object hierarchy, there is another instance where a TestObject may be returned. Some script API invoke a method in the SUT that has a result which then needs to be marshaled (brought back) to the script that is playing. Typically these results would be copied into another object that we know about and understand. These objects are instances of value classes.
  For example, getting a text property in Internet Explorer results in a string of some sort being created in the SUT. Since we know and understand these strings we can transfer the result to a java.lang.String which would show up as the result in the script playback process. You would get a copy of the data that could be represented in the script rather than the actual data. A TestObject is returned for results that we do not know how to generically express.
  Note: The RFT recorder and wizards only generates code that returns value classes (never TestObjects). Results of getProperty() and invoke() may return a TestObject. The method getNonValueProperties() returns a hashtable keyed off of all the property names and containing TestObjects representing all property values for which no value class exists.
Other questions on extracting child objects or how to perform certain events on those GUI Objects, please contact IBM Rational Support at 800-IBM-SERV for more information.

[/td]
[/tr]

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-122139-1-1.html 上篇帖子: 伸向你的黑手:我要玩你―IBM:老Hu的玩机经历(8月8日更新) 下篇帖子: 运动目标检测、阴影检测及目标跟踪中用得到的标准测试视频下载(大量IBM提供视频)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表