运行完自动测试用例后,测试结果自动生成于测试工具目录下面。这样会覆盖原先的文件,不利于项目的跟踪和信息的交流。所以,我们的测试系统会将测试报告发布到 Web 管理站点。用户只需按照上面的时间点击链接,就可以看到每次测试的运行结果(参见图 4)。
图 4. 测试报告界面Selenium 在系统中的应用
自动测试模块式该系统的一个核心部分,它使用了 Selenium 这个工具。Selenium 是一款针对 Web 产品的测试工具。它根据测试脚本,向浏览器发出指令,代替人手工点击界面之苦。Selenium 有三类命令:动作命令(Action)、辅助命令(Accessor)、断言(Assertion)。动作命令可以向应用程序发出指令,比如点击按钮;辅助命令检查当前应用程序的状态并保存于变量中;断言类似于单元测试中经常使用的 Assert 方法,但是在 Selenium 中还有许多结合 Xpath 获取元素属性的方法。
通过这些命令,用户可以方便地实现对网页的各类操作、定位网页上面的元素并判断元素的值。此外,Selenium 有两个主要的运行模式:Selenium Core 和 Selenium Remote Control。
Selenium Core 将测试用例以 Iframe 形式嵌入一个 TestRunner 页面(参见图 5),然后将它们上传到和应用程序一起的 Web 服务器端。用户可以使用右上角的 Selenium TestRunner 控制模块来操作测试脚本,获得测试结果。
图 5. Selenium Core 实例Selenium Remote Control 更加适合测试复杂的基于 Ajax 技术的应用程序。它提供一个 Selenium Server 服务器,作为应用程序客户端的代理向应用程序的服务器端发送请求(参见图 6)。在这种模式下,测试人员可以编写一些测试脚本来完成一些复杂的测试。
图 6. Selenium Remote Control 原理与 IBM 的 Rational Functional Tester 工具相比,Selenium Remote Control 有三个主要特点:
- Selenium 基于 Http 协议来实现。它根据测试脚本提供的 Xpath 定位网页上面的元素并对其进行操作,就如我们通常使用绝对和相对路径查询操作系统文件一样;IBM 的 Rational Functional Tester 则基于对象模型设计实现的。它抓取浏览器在屏幕上实时展现的对象集合,根据用户输入的元素属性在上面寻找可能的对象。实践证明,当页面非常复杂时,这个方法不精确高效。
- Selenium 是一个开源项目,可编写测试脚本的 API 包支持好几种语言,包括 Java, C++, .Net, Python 等;IBM 的 Rational Functional Tester 需要 license,并且只支持 Java。
- Selenium 在运行时使用 JavaScript 向应用程序发出测试命令,所以它对当前浏览器的位置和电脑的屏幕没有要求;IBM 的 Rational Functional Tester 需要获得当前浏览器和电脑屏幕的位置,要求屏幕始终打开。这需要人围的支持,提高项目开发的成本。
本测试模块运用 Selenium Remote Control 的模式,新建了一个 Java 项目,编写了一系列 Java 的测试脚本。项目的目录结构参见图 7。
图 7. 测试源代码文件结构该项目结构类似于普通的 Java 项目。其中,我们导入了运行 Selenium Remote Control 所需的 jar 包。另外,build 目录下的 test-output 是每次运行后测试报告生成的地方。文件 build.xml 中定义了很多 Ant 的任务,用来编译和运行测试脚本。
下面是一个测试脚本的事例,它将一个集群加入管理服务列表。Selenium 的测试脚本类似于一般的 Junit 测试用例。首先,需要新建一个 Selenium 的会话。这个会话需要的参数包括 Selenium 代理服务器的地址(selenSrvrAddr)、端口(4444)、需要测试的 Web 应用的服务器地址(bpath)以及 Web 应用在服务器上面的相对路径(appPath)。然后,定义具体方法,对应用程序进行操作。比如在下面事例中使用 Open 函数打开页面,选择页面上面的一系列 Frame(这里给出 Frame 的 name 就可以,因为它在页面上是唯一的),然后点击链接(这个链接通过属性 Link 来定位的)。最后,记得关闭这个会话。
清单 6.测试脚本事例import org.TestNG.annotations.AfterClass; import org.TestNG.annotations.BeforeClass; import org.TestNG.annotations.Parameters; import org.TestNG.annotations.Test; import com.thoughtworks.selenium.DefaultSelenium; import com.thoughtworks.selenium.Selenium; public class TestClusterAddPage { private Selenium driver = null; @Parameters({"selen-svr-addr", "brwsr-path", "aut-addr"}) @BeforeClass private void init(String selenSrvrAddr, String bpath, String appPath){ driver = new DefaultSelenium(selenSrvrAddr, 4444, bpath, appPath); driver.start(); } @Parameters({"cluster-ip", "cluster-username", "cluster-pwd"}) @Test public void testAddCluster(String ip, String username, String password){ driver.open("/ica/Login"); driver.selectFrame("rootFrame"); driver.selectFrame("consoleWorkAreaFrame"); driver.selectFrame("rootFrame"); driver.selectFrame("consolePortfolioFrame"); driver.selectFrame("taskEntriesFrame"); driver.click("link=Clusters"); … .. } @AfterClass private void stop(){ driver.stop(); } } |
从以上事例可以看出,Selenium 在定位页面上元素时比较随机。有时可以使用元素的 name 属性,有时可以使用元素的 id 属性。为此,项目组可以为客户端页面上的元素定义唯一的属性,方便 Selenium 测试。
使用 Selenium Remote Control 模式需要在运行脚本前后启动和停止 Selenium Server 服务器。这里我们在 build.xml 中定义了一个任务名为 start-selenium。该任务第一步就是启动 selenium server 服务器,第二步是调用 TestNG 配置的测试脚本,最后是停止 selenium server 服务器。整个流程比较清晰明了(参见以下代码)。
清单 7.Selenium 流程<target name="start-selenium"> <java jar="lib/selenium-server-1.0-beta-2/selenium-server.jar" fork = "true" spawn = "true"/> <Antcall target="run-task-jar"/> <get dest="${test.output}/results.txt" src="http://localhost:4444/selenium-server/driver/?cmd=shutDown" /> </target> |
TestNG 在配置自动测试脚本中的作用
本测试系统还使用 TestNG 工具来辅助配置自动测试。TestNG 是测试 Java 应用程序的框架之一。它通过一些语义注释来传递测试的参数,定义测试脚本的顺序并配置运行时的性能。用户可以通过配置来生成各式测试报告,十分方便。
TestNG 要求将所有要运行的测试用例都记录在一个叫 testng.xml 的文件中(参见以下代码)。然后根据该文件中的测试用例顺序依次执行测试。用户还可以根据需要在测试用例的具体方法中标识 @BeforeClass,@AfterClass 等语义,更加具体得定义测试顺序。
为方便配置测试 Web 应用程序,我们将所使用的浏览器和应用程序所部署的 IP 地址作为参数定义在 testng.xml 中。这些参数由 parameter 定义,通过 @Parameters 传递到函数中(参见上文)。具体的测试脚本由 Classes 元素中的 Class 来定义。
清单 8.testng.xml<!DOCTYPE suite SYSTEM "http://beust.com/TestNG/TestNG-1.0.dtd" > <suite name="My test suite"> <test name="SVCGUI unit test"> <parameter name="selen-svr-addr" value="localhost"></parameter> <parameter name="aut-addr" value="http://9.9.9.9:9080"></parameter> <parameter name="brwsr-path" value="*firefox"></parameter> <parameter name="cluster-ip" value="1.1.1.1"></parameter> <parameter name="cluster-username" value="admin"></parameter> <parameter name="cluster-pwd" value="abc"></parameter> <classes> <class name="src.cluster.TestClusterAddPage"/> <class name="src.cluster.TestClusterDeletePage"/> <class name="src.user.TestUserListPage"/> </classes> </test> </suite> |
在上文的事例中,定义了一个叫 My test suite 的测试组,其中包括三个测试脚本。用户可以根据需要在同一个文件中定义其他测试组(suite),或者在一个测试组中定义更多的测试脚本集(classes)。
系统的 Web 管理站点会罗列出该文件中的 class 元素的 name 属性值(参见图 8)。然后让用户自由选择需要的测试用例,保存成一份新的 testng.xml 文件。接着,用户可以选择马上执行自动测试或者保存到下一次系统运行下载流程时执行。
图 8. 测试实例管理界面TestNG 还能够为系统自动生成一份漂亮的测试报告。我们可以在 build.xml 中给出报告的存放地址和形式(包括 html/text 等,参见如下代码)
清单 9.build.xml<target name="compile" description="compile the examples" depends="prepare"> <javac debug="true" fork="true" source="1.5" classpathref="cp" srcdir="${basedir}/src" destdir="${basedir}/build/classes" /> </target> <target name="testjar" description="make a test jar with the property file and the classes we need in it"> <jar destfile="${basedir}/example.jar"> <fileset dir="${basedir}/build/classes" includes="**/*.class"/> <fileset file="${basedir}/TestNG.xml"/> </jar> </target> <target name="run-task-jar" depends="compile, testjar" description="run examples using TestNG task with just xml"> <testng classpathref="cp" outputdir="${test.output}" testjar="${basedir}/example.jar"/> </target> |
在以上事例中有三个任务,compile/testjar/run-task-jar。这三个任务中 run-task-jar 是主要的任务,它调用了 TestNG 的语义 <testng>,并给出测试报告的生成目录,以及测试脚本的所组成 jar 包名。
使用 Flex 实现的管理站点
Web 管理站点在整个测试系统中起到了画龙点睛的作用。它的功能涵盖了下载控制,测试脚本控制和测试报告发布。用户可以通过它来新建,修改,删除和浏览各模块的当前配置。当然,也可以根据项目的需要添加其他模块,比如播放产品的 demo,显示项目的进度等等。
该 Web 管理站点由 Flex 技术实现。基于前文的介绍,作为一个 RIA 技术,Flex 可以帮助我们快速实现一个丰富多彩、灵活互动的客户端(整体效果参见图 9)。
图 9. 图形管理界面站点的客户端定义了一个新的布局器 PodLayoutManagers, 它让用户通过 XML 文件来配置当前显示的视图(view),各个视图所包含的模块(pod)(参见以下代码)。每种 view 和 pod 类型都有自己的 ID。此外 , 每个 pod 模块需要定义所属的类型。用户可以自定义新类型,但是每个类型都要继承于 PodContentBase 控件,并给出模块的标题(title), 读写的 XML 文件(dataSource)。有些类型还详细到具体读取的 XML 文件中的属性 , 以及它们在表格上门显示的列名。比如,在 XML 中我们定义了一个管理视图,叫做 Project Management Console,它有四个模块,分别是 list, form、case 和 film 类型。其中 , 第二个 pod 标题为“Download To Do”, 读取的数据文件为 data 目录下的 tasks.xml。它会读取文件中的 Name、Type、Weedday、time、Source Url、Target Url 属性 , 并将它们以 name、type、weekday、time、source、target 显示在列表中(参见上文) 。
清单 10.tasks.xml<?xml version="1.0" encoding="utf-8"?> <views> <view id="view1" label="Project Management Console"> <pod id="pod1" type="list" title="Unit Test Report" dataSource="data/testreport.xml" selectedViewIndex="1"/> <pod id="pod2" type="form" title="Download To Do" dataSource="data/tasks.xml" labels="Name,Type,Weedday,time,Source Url,Target Url" dataFields="name,type,weekday,time,source,target" /> <pod id="pod3" type="case" title="Test Case" dataSource="data/TestNG.xml" labels="Test Case" dataFields="name" /> <pod id="pod4" type="film" title="Product demo" dataSource="data/news.xml"/> </view> </views> |
Form 和 case 类型可以选择两种显示的方式:Grid 和 Form。在 Grid 模式下,模块会以列表形式显示数据。在 Form 模式下,模块会显示一个表单,用户可以新建,修改和删除一条记录(参见图 10)。
图 10. 下载管理界面在这个页面中,首先要在 PodContentBase 控件中加入一个 HBox 来切换两个不同的视图。然后定义一个 ViewStack,并在其中加入两个控件:VBox 和 Canvas。VBox 显示表单,而 Canvas 中用 DataGrid 读取 dataFields 中的数据并以表格方式显示。而页面上面的 Action 主要在 Script 中实现。具体实现参见图 11:
图 11. 管理界面页面代码Flex 可以与各类服务器端技术相结合。该 Web 管理站点采用 J2EE 作为服务器端技术,通过 serve let 同客户端通信,完成对各 XML 配置文件的修改。由于篇幅有限,具体实现方式可以参考文章《 Flex 开发入门》。
总结
本文向大家详细介绍了一个智能的 Web 界面测试系统。它的四个主要模块配置灵活、运行高效,可以帮助团队完成 Web 界面的各类测试。我们的开发和测试人员不必再为枯燥乏味的界面操作而叹气。此外,友好的 Web 管理站点进一步体现了系统的灵活、高效、开放的特点。该测试系统的另一个特点就是可扩展性。项目组可以根据自身的需要丰富管理站点的功能,引入一些项目进度、人员时间等管理模块,使项目内部交流更加精密。
希望本文能为相关的软件研发团队提供一些技术和设计上的启发。
文章来源于领测软件测试网 https://www.ltesting.net/