转自:http://www.ibm.com/developerworks/cn/rational/09/userationalfunctionaltestereffectively/index.html
IBM Rational Functional Tester 提供了一些特性,用户可以使用这些特性来有效测试 GUI 程序。IBM Quality Software Engineering(QSE)团队引入了一个层级结构框架,也就是所谓的 QSE 框架,以让维护变得更加容易。该框架使用 Rational Functional Tester 对象认知特性。本文向您展示了怎样扩展 QSE 框架,以及怎样使用 Rational Functional Tester 的特性来提高测试的生产效率。您还可以得到可以有效支持测试多语言程序的建议。
IBM® Rational® FunctionalTester 提供了自动化测试的特性。为了使用记录特性,您可以记录一次测试活动并将其保存为测试脚本。在此之后,不论何时您想要执行相同的测试时,都可以运行该测试脚本。
在您测试却想要输入数据时,您可以在记录期间使用测试数据汇特性。如果您使用了测试数据汇特性,那么您就可以在运行测试脚本之前更改输入数据了,而不需要重复记录该测试活动。您可以使用验证点,Rational Functional Tester 会使用它来比较实际值和预期值,然后生成一个带有详细信息的报告,信息会向您展示是否得到了预期值。但是,使用记录特性您也许会关注,当测试的程序被更改过时,您也许会需要重新记录测试活动。
为了降低操作的难度,IBM Quality Software Engineering(QSE)团队引入了一个层级结构的框架,也就是所谓的 QSE 框架。该 QSE 框架会将 GUI 对象与测试用例隔离开来。Rational Functional Tester 提供了 Test Object Map 特性,使用该特性可以获得 GUI 对象。通过使用 GUI 对象的方法可以执行对 GUI 的操作。QSE 框架由以下三层组成。
- appobjects 文件包含了测试对象映射特性获取的 GUI 对象。
- tasks 文件夹包含的程序,通过使用 appobjects 文件夹中的对象来执行 GUI 操作。GUI 操作可以当做任务来分类和实施。例如,注册进程可以当做任务来实施。
- testcases 文件夹包含了程序,您可以使用 tasks 文件夹中的程序来执行测试用例,并且可以记录结果。
您可以使用 QSE 框架来提高维护性。如果想要得到关于 QSE 框架的更多信息,可以引用参考资源章节中的 An Object-Oriented framework for IBM Rational Functional Tester 项。
本文向您展示了通过扩展 QSE 框架和使用 Rational Functional Tester 特性(例如测试数据汇和验证点),怎样更加有效地自动化测试。本文还向您介绍了一些技巧,这些技巧是关于怎样测试支持多种语言的程序的。
考虑一下测试图 1 中所示的程序。
在这个 GUI 中,您可以选择 Actions > Create New Set 菜单项,如图 2 所示。通过 Test Object Map 特性可以获得这些对象。
对于 QSE 框架提供的 jar 文件,您可以定义如图 3 和列表 1 所示的方法,以得到 Test Object Map 特性获取的 GUI 对象。
package appobjects; import resources.appobjects.MainGUIHelper; import ibm.widgets.*; import ibm.widgets.ancestors.*; import ibm.widgets.swt.*; import com.rational.test.ft.*; import com.rational.test.ft.object.interfaces.*; import com.rational.test.ft.script.*; import com.rational.test.ft.value.*; import com.rational.test.ft.vp.*; public class MainGUI extends MainGUIHelper { public ToggleWidget getActions() { TestObject to = actions(ANY, NO_STATE); return new ToggleWidget(to); } public ToggleWidget getActionsCreateNewSet() { TestObject to = actionsCreateNewSet(ANY, NO_STATE); return new ToggleWidget(to); } public ToggleWidget getConfigureGroupDiscoveryOptions() { TestObject to = configureGroupDiscoveryOptions(ANY, NO_STATE); return new ToggleWidget(to); } public ToggleWidget getCreateNewView() { TestObject to = createNewView(ANY, NO_STATE); return new ToggleWidget(to); } public SubitemWidget getGrdTree() { TestObject to = grdTree(ANY, NO_STATE); return new SubitemWidget(to); } public ToggleWidget getRunGroupDiscovery() { TestObject to = runGroupDiscovery(ANY, NO_STATE); return new ToggleWidget(to); } public ToggleWidget getRunTraceAnalyzer() { TestObject to = runTraceAnalyzer(ANY, NO_STATE); return new ToggleWidget(to); } // ----------------------------------------- public void testMain (Object[] args) { // Unit testing can go here // (will be deleted next time ClasGenerator is run) } } |
列表 2 中的程序模拟点击 Actions 菜单,然后点击 Create New Set 子菜单。
MainGUI mainGui = new MainGUI(); mainGui.getActions().click(); mainGui.getActionsCreateNewSet().click(); |
正如本例所示,您可以通过使用 GUI 对象来轻松控制 GUI。但是,找到用于执行 GUI 操作的方法会很困难。图 4 显示了一个范例:当您右击树形结构的节点时,考虑一下这个例子。
在树形结构中,您不能将每一个节点当做一个对象。如图 5 所示,您需要得到树对象,然后使用方法中的一种以右击树的节点。
如果您不知道 GUI 对象是怎样执行 GUI 操作的(就像本例),那么您可以使用记录特性,然后引用生成的程序。在本例中,当您记录右击节点时,您可以得到如列表 3 所示的程序。
public void testMain(Object[] args) { // Frame. Database Relationship Analyzer grdTree().click(RIGHT, atPath("SAMPLE->ORDER->TRACE_ANALYSIS")); } |
在 tasks 文件夹中编写这种程序并不是十分有效。相反,在类中编写通用方法以模拟以上的操作就比较合适了,它继承了 appobjects 文件夹中的 GUI 对象类。这种类型的类并不需要当做一个 Rational Functional Tester 脚本来创建:将其当做一个 Java™类来创建已经足够了。创建一个文件夹,例如一个名为 apputils 的文件夹,以存储这种类型的类。列表 4 中的程序显示了右击树节点的通用方法。 MainGUIUtil 类继承了 MainGUI 类。 MainGUI 类包含了主窗口中的 GUI 对象,它位于 appobjects 文件夹之下。前面使用的 grdTree 方法,可以用于将树对象替换为 MainGUI 类中定义的书对象,在本例中是 getGrdTree 方法。
public class MainGUIUtil extends MainGUI { public void rightClickView(String dbName, String setName, String viewName) { String s = dbName + "->" + setName + "->" + viewName; getGrdTree().click(RIGHT, atPath(s)); } |
通过使用这样的方法,tasks 文件夹中的程序可以和 GUI 操作一样得到直觉地实施。
对于 QSE 框架,输入数据的过程如下所示。
- 通过使用 Test Object Map 特性来获取每一个输入区域,以得到它的 GUI 对象。
- 定义方法以得到 GUI 对象。
- 通过使用 GUI 对象的方法来设置输入值。
您可以使用 Test Datapool 特性,来有效地执行数据输入操作。例如,图 6 显示了一个带有输入区域的 GUI。考虑一下该 GUI 中的输入数据。
在打开该 GUI 之后,开始记录,然后通过选择 Insert Data Driven Commands 获取该窗口。在获取之后,暂停您的记录操作,输入假程序数据以激活 OK 按钮,重命名记录操作,点击 OK,然后停止记录。当您这样做时,会生成如图 7 和列表 5 所示的程序。如果您想要对由多个面板组成的向导应用该技术,那么就在每一个面板中插入数据驱使的命令,这样您就可以参数化所有的输入区域了。
图 7. 随着 Test Datapool 特性一起生成的程序
package recordingobjects; import resources.recordingobjects.RunTraceAnalyzerGUIRecordingHelper; import com.rational.test.ft.*; import com.rational.test.ft.object.interfaces.*; import com.rational.test.ft.object.interfaces.SAP.*; import com.rational.test.ft.object.interfaces.WPF.*; import com.rational.test.ft.object.interfaces.dojo.*; import com.rational.test.ft.object.interfaces.siebel.*; import com.rational.test.ft.object.interfaces.flex.*; import com.rational.test.ft.script.*; import com.rational.test.ft.value.*; import com.rational.test.ft.vp.*; public class RunTraceAnalyzerGUIRecording extends RunTraceAnalyzerGUIRecordingHelper { public void testMain(Object[] args) { // Data Driven Code inserted on 2009/02/28 // schemaName().setText(dpString("SchemaName")); tableName().setText(dpString("TableName")); startDate().setText(dpString("StartDate")); startTime().setText(dpString("StartTime")); endDate().setText(dpString("EndDate")); endTime().setText(dpString("EndTime")); ok().click(); } } |
如果您定义了一个包含该程序的方法,那么其他的程序就可以调用该方法了。当您调用该方法时,测试数据汇中定义的值会在合适的区域中得到设置。正如您在图 7 和列表 5 中看到的那样, dpString 方法用于得到来自测试数据汇的值。
如果您更改了方法,以通过方法参数传递输入值,那么该方法就可以得到通用的应用了。在本例中,如果您为开始时和结束时使用了测试数据汇值,并通过方法参数动态地设置其他的输入值,那么方法如列表 6 所定义的那样。
public void runTraceAnalyzer(String schema, String table, String startDate, String endDate) { schemaName().setText(schema); tableName().setText(table); startDate().setText(startDate); startTime().setText(dpString("StartTime")); endDate().setText(endDate); endTime().setText(dpString("EndTime")); ok().click(); } |
如果有一些结果会显示在 GUI 中,那么通过使用验证点特性,就可以很容易地比较实际值和预期值了。
例如,如果您想要得到如图 8 所示的表格,那么就在记录开始之后,将表格当做验证点,然后停止记录。它会产生如图 9 和列表 7 所示的程序。
图 8. 包含一些结果的表格
图 9. 生成验证点特性的程序
package verificationpoints; import resources.verificationpoints.TestResult1Helper; import com.rational.test.ft.*; import com.rational.test.ft.object.interfaces.*; import com.rational.test.ft.object.interfaces.SAP.*; import com.rational.test.ft.object.interfaces.WPF.*; import com.rational.test.ft.object.interfaces.dojo.*; import com.rational.test.ft.object.interfaces.siebel.*; import com.rational.test.ft.object.interfaces.flex.*; import com.rational.test.ft.script.*; import com.rational.test.ft.value.*; import com.rational.test.ft.vp.*; public class TestResult1 extends TestResult1Helper { public void testMain(Object[] args) { table().performTest(ResultTableVP()); } } |
复制以上的程序以创建如列表 8 所示的方法。如果您调用了该方法,那么 Rational Functional Tester 会自动比较实际值和预期值。
public void verifyResult() { table().performTest(ResultTableVP()); } |
如果您想要动态地更改预期值,那么您可以使用 IFtVerificationPointvpManual(java.lang.String vpName, java.lang.Object expected, java.lang.Object actual).performTest method。vpManual 方法有三个 参数。第一个参数是设置项目中独一无二的验证点名,第二个参数是设置预期的对象,而第三个参数是设置一个实际对象。如果您想要比较如本例中那样表格中的值,那么您可以使用vpManual方法中第二个和第三个参数的 com.rational.test.ft.vp.impl.TestDataTable类对象。您可以创建如列表 9 所示的预期对象。您还可以指定比较的区域,它是在 setComparisonRegions方法中完成的。
TestDataTable tbl = new TestDataTable(); tbl.setColumnHeader(0, "Table Name"); ... tbl.insert(new String[7], 0); tbl.setCell(0, 1, "CUSTINFO"); ... TestDataTableRegions regions = new TestDataTableRegions(); regions.addRegion(TestDataTableRegion.allCells()); tbl.setComparisonRegions(regions.getRegions()); |
在接下来的例子中,您可以使用验证点对象作为预期对象,它是通过获取 GUI 表格作为上例中的验证点得以创建的。它将会创建一个预期的对象。接下来,编辑该对象的值。为了得到实际值,您可以使用测试对象映射获取的table对象的getTestData(String testDataType)方法,如列表 10 所示。 testDataType 参数拥有显示在验证点窗口中的 type属性。您可以在图 10 中看到它。在本例中,该值是“可视的内容”。
Public void verifyResult() { TestDataTable tbl = (TestDataTable)ResultTableVP().getBaselineData(); tbl.setCell(0, 1, "CUSTHIST2"); vpManual("VP1", tbl, table().getTestData("visible contents")).performTest(); } |
在本程序中,“CUSTHIST2”在一个单元中得到设置,以前它是“CUSTHIST”。运行这种方法会产生一个错误,您会得到如图 10 所示的信息。
前面的范例讨论了 table 对象。可以比较的其他对象如表格 1 所示。
GUI 类型 | 类 |
---|---|
树 | com.rational.test.ft.vp.impl.TestDataTree |
列表 | com.rational.test.ft.vp.impl.TestDataList |
菜单栏 | com.rational.test.ft.vp.impl.TestDataTree |
Character 字符串 | 字符串 |
在 tree 对象中,列表 11 显示了一个添加节点到作为验证点获取的 tree 对象的程序。
public void verifyResult() { TestDataTree tree = (TestDataTree)GRDTreeVP().getBaselineData(); TestDataTreeNodes nodes = (TestDataTreeNodes)tree.getTreeNodes(); TestDataTreeNode node = (TestDataTreeNode)nodes.getRootNodes()[0]; node = (TestDataTreeNode)node.getChild(0); node = (TestDataTreeNode)node.getChild(0); node = (TestDataTreeNode)node.getChild(0); TestDataTreeNode node2 = new TestDataTreeNode(); node2.setNode("GROUP2"); TestDataTreeNode[] n = new TestDataTreeNode[2]; n[0] = (TestDataTreeNode)node.getChild(0); n[1] = node2; node.setChildren(n); vpManual("TreeVP1", tree, grdTree().getTestData("tree")).performTest(); } |
当您运行该程序时,您会得到如下的信息(图 11)。
在 list 中,列表 12 显示了向作为验证点获取 list 对象添加项的程序。
public void verifyResult() { TestDataTree tree = (TestDataTree)GRDTreeVP().getBaselineData(); TestDataTreeNodes nodes = (TestDataTreeNodes)tree.getTreeNodes(); TestDataTreeNode node = (TestDataTreeNode)nodes.getRootNodes()[0]; node = (TestDataTreeNode)node.getChild(0); node = (TestDataTreeNode)node.getChild(0); node = (TestDataTreeNode)node.getChild(0); TestDataTreeNode node2 = new TestDataTreeNode(); node2.setNode("GROUP2"); TestDataTreeNode[] n = new TestDataTreeNode[2]; n[0] = (TestDataTreeNode)node.getChild(0); n[1] = node2; node.setChildren(n); vpManual("TreeVP1", tree, grdTree().getTestData("tree")).performTest(); } |
当您运行该程序时,会得到以下的信息(图 12)。
为了测试多个语言的程序,您可以使用包含密钥和值对( [KEY]=[VALUE]),此处该值会显示在 GUI 中。资源文件的一个范例是在 Java 的 ResourceBundle 类中使用的资源文件。配置该文件的步骤如下所示。
- Rational Functional Tester 的 ivory.properties 文件中以下的属性的目录被激活。
# When enabled this property allows string look up in a localized string table, if available rational.test.ft.services.enable_localization=true
- 在将文件的基底名字更改为 Rational Functional Tester 项目名之后,包含密钥和值对的程序的资源文件,会复制到 Rational Functional Tester 项目的资源文件夹之下。显然创建文件也是可行的。资源文件名格式为:
- [Rational Functional Tester project name]_[language].properties
- DRAProject_ja.properties
- 重启 Rational Functional Tester。
- 打开测试对象图,然后将作为 GUI 显示值的属性值,更改为资源文件的密钥名。有一些属性名,例如下面的,有 GUI 显示值。
- accessibleContext.accessibleName
- .captionText
- name
- text
例如,将英文资源文件复制到日本资源文件中,然后在每一个值的前面添加一些日本字符。您可以在如图 13 中的 GUI 中这样做。
打开测试对象图,然后将作为 GUI 显示值的属性值更改为资源文件的密钥名字,如图 14 所示。
当您按住 Enter 键时,密钥名就会更改为合适资源文件中的实际值,如图 15 所示。密钥名就存储在里面,值会根据语言环境而发生动态的变化。当您双击属性值,以再次切换编辑模式时,您可以看到资源文件的密钥名。当您更改资源文件的一些值时,然后重启 Rational Functional Tester,在测试对象图中您可以看到更改的值。
接下来的 name 属性,具有与上级菜单名相联系的值,由下划线(“_”)隔开。所以它的权重会更改为 0(图 16)。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/17117101/viewspace-618397/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/17117101/viewspace-618397/