简介:在测试自动化中,会将测试脚本和相关的测试框架绑定到接受测试的应用程序底层域。然后,判断是否可以跨域使用框架提供的相同记录对象、脚本和可重用函数成为了一个难题。要克服这个问题,关键是使得自动化测试脚本与域无关。其结果是,可以跨不同的测试应用程序域使用相同的应用程序对象、测试脚本和可重用函数,无需考虑它们是否是 HTML、Java、Microsoft .NET、Microsoft Windows 等。
问题:域依赖性阻碍了脚本的重用
无论测试自动化开发人员通过记录回放还是传统描述性编程来创建脚本,测试脚本和可重用函数都会绑定到接受测试的应用程序的底层域。那么,我们如何确保编写功能的工作(例如,将文本设置到某个 Edit Box)在每次域转变时都不会重复?,您可能正在为某个基于 Web 的应用程序编写测试脚本,并且每次都以 HTML 格式针对域进行记录和编写脚本。随后,您可能需要使用您之前已经编写代码的相同功能,但要跨一个基于 Java 的应用程序。
当我们使用记录回放机制时,所有与应用程序交互的测试对象都被记录和存储在 IBM? Rational? Functional Tester 对象映射中。图 1 显示了一个这样的示例,其中应用程序域被硬编码为 Java。
图 1. 以 Java 作为应用程序域的一个对象映射
类似地,如果使用描述性编程机制开发测试脚本,函数会被绑定到某个特定的应用程序域。在这种情况下,实现测试函数可重用性会变得具有挑战性。
因此,好使脚本和底层测试对象与应用程序域无关。
解决方案:使用描述性编程实现跨域兼容性
Rational Functional Tester 提供一种动态机制,在脚本回放过程中获得测试对象的引用。find() API 使这一点成为可能,因为它引用接受测试的应用程序中的对象时,无需在测试对象映射中记录或硬编码该对象。该 API 找到父测试对象或顶层测试对象,并查找一个匹配的子对象。
使用 find() API 识别域或顶层对象
鉴于这一点,通过描述性编程实现测试自动化框架以及使用 find() API 可以有助于识别接受测试的应用程序的域或顶层对象,并相应地找到该对象下面的一个匹配的子测试对象。清单 1 中的代码说明了该过程。
清单 1. 为当前应用程序设置测试域值
String myDomainName = "";
//For HTML Browser - Set the Application Domain Name myDomainName = "Html.HtmlBrowser";
OR
//For HTML Dialog - Set the Application Domain Name myDomainName = "Html.Dialog";
OR
//For Swing JDialog - Set the Application Domain Name myDomainName = "javax.swing.JDialog ";
OR
//For Swing JFrame - Set the Application Domain Name myDomainName = "javax.swing.JFrame";
OR
//For Custom Parent Objects - Set the Application Domain Name myDomainName = " com.ibm.retail.rma.res.ui.config.MasterAgentInfoDlg ";
在 Rational Functional Tester 代码中,当应用程序域被设置后,顶层测试对象可以被解析为它所要映射到的父对象类型。清单 2 中的代码片段说明了这一点。在本例中,如果域是 HTML Browser,顶层对象被解析为 BrowserTestObject;如果域是 HTML Dialog,顶层对象被解析为 TopLevelTestObject,等等。
清单 2. 将父对象解析为应用程序域
/* Parse the Top Level Test Object to the corresponding test object type based * on the domain name that was set */
TestObject myDomain;
if (myDomainName.equalsIgnoreCase("Html.HtmlBrowser")) { myDomain = (BrowserTestObject) returnTO(".class", "Html.HtmlBrowser"); } else if (myDomainName.equalsIgnoreCase("Html.Dialog")) { myDomain = (TopLevelTestObject) returnTO(".class", "Html.Dialog"); } else if (myDomainName.equalsIgnoreCase("javax.swing.JDialog")) { myDomain = (TopLevelTestObject) returnTO(".class","javax.swing.JDialog"); } else if (myDomainName.equalsIgnoreCase("javax.swing.JFrame")) { myDomain = (TopLevelTestObject) returnTO(".class", "javax.swing.JFrame"); } else if (myDomainName.equalsIgnoreCase ("com.ibm.retail.rma.res.ui.config.MasterAgentInfoDlg")) { myDomain = (TopLevelTestObject) returnTO(".class", "com.ibm.retail.rma.res.ui.config.MasterAgentInfoDlg"); }
/* This function returns the 1st instance of a test object based on the * recognition property and the property value provided. If the test object * is not found null will be returned. */ public TestObject returnTO(String recognitionProperty, String recognitionPropertyValue,) { RootTestObject rTO = getRootTestObject(); TestObject[] TOs = rTO.find(atDescendant(recognitionProperty, propValue)); TestObject returnTO = null; int numOfObjects = TOs.length; if (numOfObjects >= 1) returnTO = TOs[0]; return returnTO; }
在将顶层测试对象解析为正确的父测试对象类型后,使用 find() API 将有助于获得该对象下面的子对象的引用。然后,您可以编写一个通用的可重用函数,该函数将以跨域的方式工作。清单 3 中的代码显示一个示例,其中定义了通用 setText 函数,无论应用程序域是 HTML、Java、.NET,还是基于当前图形化用户界面技术的任何其他域,该函数均有效。
清单 3. 通用的跨域 setText() 函数
public boolean setTextGuiTestObject(TestObject myDomain, String recognitionProperty, String recognitionPropertyValue, String valueToSet) { boolean status = true; try { TestObject[] TOs = null; TOs = myDomain.find(atDescendant (recognitionProperty, recognitionPropertyValue)); int numOfObjects = TOs.length;
if (numOfObjects >= 1) { TextGuiTestObject myGTO1 = null; myGTO1 = (TextGuiTestObject) TOs[0]; myGTO1.waitForExistence(2500, 0.10); if (myGTO1.exists()) { System.out.println("Setting Text: " + valueToSet); myGTO1.click(); myGTO1.setText(text); } } myGTO1.unregister(); } catch (Exception e) { System.out.println("Unable to set Text :: " + e.toString()); status = false; } return status; }
在本例中,该函数没有绑定到任何应用程序域。相反,在将值设置到 Text Box 之前,应用程序域作为一个输入参数被传递给该函数。因此,只要提供了正确的域、标识属性以及要设置的值,自动化脚本能够在任何域的编辑框中设置文本。
当应用程序域经常改变时使用该方法
然而,该自动化测试脚本开发模型还解决了另一个方面的问题。
在自动化测试中,接受测试的应用程序常常会从一个域转变到另一个域。以下是一个示例场景:
● 您在一个 HTML、基于 Web 的应用程序上开始自动化。在这种情况下,顶层测试对象是:HTML.Browser。
● 在脚本中,某个操作启动了一个 HTML 对话框。从 Rational Functional Tester 的透视图可看到,顶层测试对象现在已经转移到 HTML Dialog。
● 在更多导航之后,这个基于浏览器的应用程序会启动了一个 Java Swing 对话,其中顶层测试对象已转换为 javax.swing.JDialog。
在所有这些情况中,如果有一个通用的操作将文本设置到各自顶层测试对象下面的子对象,这种使函数与域无关的方法将会有很大的帮助。您需要做的只是传递与该操作相关的域。是说,您首先传递一个 HTML.Browser、HTML.Dialog,然后再传递 javax.swing.JDialog。代码清单 4 说明了这一点。
清单 4. 顶层应用程序域经常改变的情况
TestObject myDomainName; String myDomainName = "";
/* * Step 1 - Set value to the text box in Html.Browser */ myDomainName = "Html.HtmlBrowser"; if (myDomainName.equalsIgnoreCase("Html.HtmlBrowser")) { myDomain = (BrowserTestObject)returnTO(".class", "Html.HtmlBrowser"); } setTextGuiTestObject(myDomain, ".id", "hostname", "StoreServer");
/* * Step 2 - Set value to the text box in Html.Dialog */ myDomainName = "Html.Dialog"; if (myDomainName.equalsIgnoreCase("Html.Dialog")) { myDomain = (TopLevelTestObject)returnTO(".class", "Html.Dialog"); } setTextGuiTestObject(myDomain, ".id", "searchIP", "9.124.45.43");
/* * Step 3 - Set value to the text box in javax.swing.JDialog */ myDomainName = "javax.swing.JDialog"; if (myDomainName.equalsIgnoreCase("javax.swing.JDialog ")) { myDomain = (TopLevelTestObject)returnTO(".class", "javax.swing.JDialog"); } setTextGuiTestObject(myDomain, ".id", "searchPort", "9443");
在一个频繁改变的应用程序域场景中,该方法非常有效。自动化脚本和函数变成可重用,因而减少了冗余。
该方法的价值的总结
您可以在商用或开源的任何自动化工具中有效地使用本文中所描述的方法。使您的脚本与域无关并不只是实现脚本的可重用性。当在某个域(如 HTML)中构建的应用程序功能被转移到另一个域(如 Java)时,它还可以使脚本运行稳定。但无论如何,在您编写测试脚本之后,它都可以在相同产品生命周期的多个版本中使用。
此外,由于这些通用函数的可重用性是使用跨域方法的结果,这些脚本和函数不会被绑定到特定产品或应用程序域。