如此说来,测试运行工具是很强大的,但是每天都得打开这个测试运行工具,并浏览你的测试页或测试集,这可能非常烦人。好在可以使用一些查询串来预置要运行的文件,让测试运行工具自动地运行测试,甚至可以向测试传递参数 !测试运行工具支持testPage 查询串 。在浏览器地址栏中键入以下地址(当然,根据具体环境可能要做相应调整),就会在浏览器中启动测试运行工具,并且预置了给定的测试:
file:///E:/jsunit2.2/jsunit/testRunner.html?testPage=E:/jsunit2.2/testSuit.html
你会看到测试运行工具运行了起来,你传递给testPage的实参会显示在file(文件)框中,如下图所示。注意,现在没有Browse(浏览)按钮了,因为你已经告诉测试运行工具要运行什么,它已经知道了。
当然,聪明的开发人员可能会对经常运行的测试集建立书签。如果你觉得testPage还不错,可能还想让autoRun 试试身手!顾名思义,可以结合autoRun和testPage来加载你最喜欢的测试页或测试集,然后它们会自动地运行,不需要再点上面的那个run按钮了。这样一个示例查询串如下所示:
file:///E:/jsunit2.2/jsunit/testRunner.html?testPage=E:/jsunit2.2/testSuit.html&autoRun=true
你应该能看到一个漂亮的绿条(见下图)。注意这里有Run按钮,因此,你可以很轻松地重新运行你的测试。同样地,能干的程序员很可能在浏览器上为这个查询增加书签。
你可能认为开发人员只需要testPage和autoRun,但实际上还不只如此!在后台,测试运行工具会把各个测试页增加到一个不可见的帧(Frame)。大多数情况下这样是可以的,但是如果有些代码必须在一个可见的帧中运行,而且你使用的是IE ,就可以告诉测试运行工具要在一个可见帧中显示你的页面。如果在查询串中加入了showTestFrame ,JsUnit就会在一个可见的帧中显示你的页面。如果你输入了showTestFrame=true ,测试页会在一个默认高度的帧中显示。如果这个默认值不合适,可以传入一个整数值,将帧高度指定为参数值(以像素为单位)。
有时,你可能想向测试页或测试集传递特定的值。可以在查询串中增加任意的行参/实参对,在测试页或测试集中使用top.jsUnitParmHash.parameterName 或top.jsUnitParmHash['parameterName'] 来获取这些值。假设按以下路径打开测试运行工具:file:/// Users/nate/projects/chapter6/web/jsunit/testRunner.html?key=1,就可以使用top.jsUnitParmHash.key或top.jsUnitParmHash['key']来访问参数key。如果你只想运行某些测试,这就很有用。下面代码清单显示了一个复杂的例子。
customSuit.html代码清单:
<html> <head> <title>Sample Test Suite</title> <script language="JavaScript" src="jsunit/app/jsUnitCore.js"></script> <script language="JavaScript"> function sampleSuite() { var suiteToRun = top.jsUnitParmHash.suite; var sampleSuite = new top.jsUnitTestSuite(); if(suiteToRun == "setUptearDownTest") { sampleSuite.addTestPage("../setUptearDownTest.html"); } sampleSuite.addTestPage("../smimpleTest.html"); sampleSuite.addTestPage("../setUpPageTest.html"); return sampleSuite; } function suite() { var testSuite = new top.jsUnitTestSuite(); testSuite.addTestSuite(sampleSuite()); testSuite.addTestPage("../exposeTest.html"); return testSuite; } </script> </head> <body> This is a simple test suite that uses custom queries. </body> </html>
可以想见,在测试运行工具中为路径追加?suite=setUptearDownTest,这会导致运行setUptearDownTest.html测试页,如果没有,则不会运行。
尽管这显然是一个简单的例子,但是从中可以看出,在不同场合下,使用定制参数来运行测试集或测试页是非常有用的。当然,你可能想为浏览器的书签文件夹增加这些特殊的查询串,以便以后使用。
还有一个有意思的标准参数是debug。不要把这个参数与debug 跟踪级别混为一谈,它们完全不同。debug参数会在使用JsUnit的开发工作中用到。对于这个查询串,你可能不会做太多工作,但是如果你很好奇,可以知道有这样一个参数(如下图)。
file:///E:/jsunit2.2/jsunit/testRunner.html?testPage=E:/jsunit2.2/customSuit.html&autoRun=true&suite=setUptearDownTest&debug
另外还有两个标准参数,只有与JsUnit服务器结合时才有意义:submitResults 和resultId 。我们稍后会讨论JsUnit服务器,到时你会更清楚地了解这两个参数,不过要知道,在测试运行工具的浏览器路径中增加submitResults=true,这会告诉JsUnit:将测试的结果发送到JsUnit的“acceptor” servlet 。这对你意味着什么?使用这个参数的话,测试运行的结果会创建结果的一个XML表示(与JUnit的XML输出有同样的结构),以便以后获取。如果向浏览器输入 file:///E:/jsunit2.2/jsunit/testRunner.html?testPage=E:/jsunit2.2/customSuit.html&autoRun=true&suite=setUptearDownTest&debug&submitResults=true 连接(注:默认会发往本机JsUnit,如果是其他服务器,则把submitResults设置成localhost:8080/jsunit/acceptor的形式即可),则测试完成后会把测试结果发送到JsUnit服务器,然后服务器根据测试传过来的结果生成XML格式的结果,并显示在浏览器中。要想看到以下结果,则还要把JsUnit服务启动起来,我这里是用的Ant命令直接拉起来的,拉起的过程图也在下面:
只有当使用submitResults=true时,resultId查询才有意义。我们只对JsUnit服务器的工作稍提及,根据我们介绍的这一点点内容,你可能可以猜出:提交到JsUnit服务器的各个测试应该有各自惟一的标识符。可以让JsUnit来提供自己的ID,但是如果必须使用你喜欢的编号,也可以通过resultId参数传递这样一个数。如果在地址栏中输入 file:///E:/jsunit2.2/jsunit/testRunner.html?testPage=E:/jsunit2.2/customSuit.html&autoRun=true&suite=setUptearDownTest&debug&submitResults=true&resultId=logfilename ,则生成的XML中id的值为logfilename,如果服务器保存了这个XML文件,则文件名也会包含logfilename。
虽然向测试运行工具传递各种参数可以较容易地完成自动化测试,但是你很快就会厌倦这样以常规方式手工地运行测试(我们可以结合 ANT 与 JUnit 来完成全自动化测试 ,以及纳入持续集成管理),特别是要考虑到多个操作系统上的多个浏览器 时,更是如此。你可能想跟踪以前运行的结果 ,以便进行审计或完成质量保证。为解决这些问题,JsUnit服务器会提供测试结果的XML日志 ,从JUnit或Ant脚本运行测试,以及在远程主机上从JUnit或Ant脚本运行测试。
利用JsUnit服务器,你只需点击一个按钮或调用一下命令,就能基于你的操作系统/浏览器运行整个测试集。另外,只需在一个重要步骤中把JavaScript的测试增加到Ant脚本中,就能使之成为构建过程的一部分。JsUnit服务器包括一组Java servlet,它们在可嵌入的Jetty开源Web服务器上运行,这样你就无需在每个主机上都配置一个Web服务器/servlet容器(因为JsUnit本身就与Jetty集成了,运行时只需用Ant启动就行了) 。一旦完成配置,这个过程就很简单了,只是按下一个按钮或调用一下命令而已!
在利用JsUnit服务器之前,需要先进行配置。为此可以修改build.xml文件,这个文件在jsunit文件夹中。这个文件的最前面有一组属性,可以修改这些属性来满足你的需要。这些变量都很好理解,详细内容请见下表。
服务器配置
环境变量 |
内 容 |
browserFileNames |
你想测试的一组浏览器可执行文件,这是一个完全路径列表,各个路径之间用逗号分隔 |
url |
测试运行工具的 URL ,包括适当的查询串来自动运行适当的测试集 |
port |
运行 JsUnit 服务器的端口,如果没有这个变量,会就使用端口 8080 |
resourceBase |
定义 JsUnit 服务器的文档根。如果是空值(一般设置),就会使用 jsunit 安装目录 |
logsdirectory |
运行测试的结果会写到这个目录。如果是空值,则默认为 jsunit/logs |
remoteMachineURLs |
指定你想在哪些远程主机上运行测试,即这些远程主机的 URL 列表,各 URL 之间用逗号分隔。这些远程主机需要已经安装配置了一个 JsUnit 服务器 |
一旦配置了测试集(或测试页)和浏览器组合,只需运行standalone_test 目标。我配置以下三个属性
<property name="browserFileNames" value="C:\Program Files\Internet Explorer\iexplore.exe" description="browserFileNames is the list of browsers in which to run tests when StandaloneTest is invoked on this machine. For a JsUnit Server, this is a mandatory property. For example: 'c:\program files\internet explorer\iexplore.exe,c:\program files\netscape\netscape7.1\netscp.exe'" /> <property id="closeBrowsersAfterTestRuns" name="closeBrowsersAfterTestRuns" value="false" description="closeBrowsersAfterTestRuns determines whether to attempt to close browsers after test runs. This is not a mandatory property. The default is true. For example: 'true'" /> <property id="url" name="url" value="file:///E:/jsunit2.2/jsunit/testRunner.html?testPage=E:/jsunit2.2/customSuit.html" description="url is the URL (HTTP or file protocol) to open in the browser. For a JsUnit Server, this is a mandatory property for a test run if the server is not passed the 'url' parameter. For example: 'file:///c:/jsunit/testRunner.html?testPage=c:/jsunit/tests/jsUnitTestSuite.html'" />
运行这个目标,会在你指定的端口上启动Jetty服务器,而一旦服务器开始运行,就会启动你指定的浏览器,而且会运行你配置的测试。当然,不必特别注意结果,如果出现一个失败或错误,它会显示在Ant任务的输出中,指出任务失败。
在命令行运行结果如下:
E:\jsunit2.2\jsunit>ant standalone_test Buildfile: build.xml standalone_test: [junit] Testsuite: net.jsunit.StandaloneTest [junit] 2009-10-20 21:37:59 org.mortbay.util.FileResource <clinit> [junit] 信息: Checking Resource aliases [junit] 2009-10-20 21:37:59 com.opensymphony.webwork.config.DefaultConfigura tion <init> [junit] 警告: Could not find webwork.properties [junit] 2009-10-20 21:38:01 net.jsunit.AbstractJsUnitServer logStatus [junit] 信息: Starting Standard Server with configuration: [junit] <configuration type="STANDARD"> [junit] <os>x86 - Windows XP</os> [junit] <ipAddress>192.168.1.100</ipAddress> [junit] <hostname>192.168.1.100</hostname> [junit] <browserFileNames> [junit] <browserFileName id="0">C:\Program Files\Internet Explorer\iexpl ore.exe</browserFileName> [junit] </browserFileNames> [junit] <closeBrowsersAfterTestRuns>false</closeBrowsersAfterTestRuns> [junit] <description /> [junit] <logsDirectory>E:\jsunit2.2\jsunit\logs</logsDirectory> [junit] <port>8080</port> [junit] <resourceBase>E:\jsunit2.2\jsunit\.</resourceBase> [junit] <timeoutSeconds>60</timeoutSeconds> [junit] <url>file:/E:/jsunit2.2/jsunit/testRunner.html?testPage=E:/jsunit2 .2/customSuit.html</url> [junit] </configuration> [junit] 2009-10-20 21:38:01 org.mortbay.http.HttpServer doStart [junit] 信息: Version Jetty/5.1.10 [junit] 2009-10-20 21:38:02 org.mortbay.util.Container start [junit] 信息: Started org.mortbay.jetty.servlet.ServletHandler@1d7ad1c [junit] 2009-10-20 21:38:02 org.mortbay.util.Container start [junit] 信息: Started ServletHttpContext[/jsunit,/jsunit] [junit] 2009-10-20 21:38:02 org.mortbay.http.SocketListener start [junit] 信息: Started SocketListener on 0.0.0.0:8080 [junit] 2009-10-20 21:38:02 org.mortbay.util.Container start [junit] 信息: Started org.mortbay.http.HttpServer@1f6f0bf [junit] 2009-10-20 21:38:03 net.jsunit.AbstractJsUnitServer logStatus [junit] 信息: Starting Test Run [junit] 2009-10-20 21:38:03 net.jsunit.AbstractJsUnitServer logStatus [junit] 信息: Launching C:\Program Files\Internet Explorer\iexplore.exe on f ile:/E:/jsunit2.2/jsunit/testRunner.html?testPage=E:/jsunit2.2/customSuit.html&a utoRun=true&submitResults=localhost:8080/jsunit/acceptor [junit] 2009-10-20 21:38:03 net.jsunit.AbstractJsUnitServer logStatus [junit] 信息: Waiting for C:\Program Files\Internet Explorer\iexplore.exe to submit result [junit] 2009-10-20 21:38:11 com.opensymphony.xwork.interceptor.component.Com ponentInterceptor <clinit> [junit] 信息: WebWork's IoC has been deprecated, please use an alternative s uch as Spring [junit] 2009-10-20 21:38:11 net.jsunit.AbstractJsUnitServer logStatus [junit] 信息: Received submission [junit] 2009-10-20 21:38:12 net.jsunit.AbstractJsUnitServer logStatus [junit] 信息: Test Run Completed [junit] 2009-10-20 21:38:12 net.jsunit.AbstractJsUnitServer logStatus [junit] 信息: Stopping server [junit] 2009-10-20 21:38:12 org.mortbay.util.ThreadedServer$Acceptor run [junit] 信息: Stopping Acceptor ServerSocket[addr=0.0.0.0/0.0.0.0,port=0,loc alport=8080] [junit] 2009-10-20 21:38:12 org.mortbay.http.SocketListener stop [junit] 信息: Stopped SocketListener on 0.0.0.0:8080 [junit] 2009-10-20 21:38:12 org.mortbay.util.Container stop [junit] 信息: Stopped org.mortbay.jetty.servlet.ServletHandler@1d7ad1c [junit] 2009-10-20 21:38:13 org.mortbay.util.Container stop [junit] 信息: Stopped ServletHttpContext[/jsunit,/jsunit] [junit] 2009-10-20 21:38:13 org.mortbay.util.Container stop [junit] 信息: Stopped org.mortbay.http.HttpServer@1f6f0bf [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 13.953 sec [junit] ------------- Standard Error ----------------- [junit] 2009-10-20 21:37:59 org.mortbay.util.FileResource <clinit> [junit] 信息: Checking Resource aliases [junit] 2009-10-20 21:37:59 com.opensymphony.webwork.config.DefaultConfigura tion <init> [junit] 警告: Could not find webwork.properties [junit] 2009-10-20 21:38:01 net.jsunit.AbstractJsUnitServer logStatus [junit] 信息: Starting Standard Server with configuration: [junit] <configuration type="STANDARD"> [junit] <os>x86 - Windows XP</os> [junit] <ipAddress>192.168.1.100</ipAddress> [junit] <hostname>192.168.1.100</hostname> [junit] <browserFileNames> [junit] <browserFileName id="0">C:\Program Files\Internet Explorer\iexpl ore.exe</browserFileName> [junit] </browserFileNames> [junit] <closeBrowsersAfterTestRuns>false</closeBrowsersAfterTestRuns> [junit] <description /> [junit] <logsDirectory>E:\jsunit2.2\jsunit\logs</logsDirectory> [junit] <port>8080</port> [junit] <resourceBase>E:\jsunit2.2\jsunit\.</resourceBase> [junit] <timeoutSeconds>60</timeoutSeconds> [junit] <url>file:/E:/jsunit2.2/jsunit/testRunner.html?testPage=E:/jsunit2 .2/customSuit.html</url> [junit] </configuration> [junit] 2009-10-20 21:38:01 org.mortbay.http.HttpServer doStart [junit] 信息: Version Jetty/5.1.10 [junit] 2009-10-20 21:38:02 org.mortbay.util.Container start [junit] 信息: Started org.mortbay.jetty.servlet.ServletHandler@1d7ad1c [junit] 2009-10-20 21:38:02 org.mortbay.util.Container start [junit] 信息: Started ServletHttpContext[/jsunit,/jsunit] [junit] 2009-10-20 21:38:02 org.mortbay.http.SocketListener start [junit] 信息: Started SocketListener on 0.0.0.0:8080 [junit] 2009-10-20 21:38:02 org.mortbay.util.Container start [junit] 信息: Started org.mortbay.http.HttpServer@1f6f0bf [junit] 2009-10-20 21:38:03 net.jsunit.AbstractJsUnitServer logStatus [junit] 信息: Starting Test Run [junit] 2009-10-20 21:38:03 net.jsunit.AbstractJsUnitServer logStatus [junit] 信息: Launching C:\Program Files\Internet Explorer\iexplore.exe on f ile:/E:/jsunit2.2/jsunit/testRunner.html?testPage=E:/jsunit2.2/customSuit.html&a utoRun=true&submitResults=localhost:8080/jsunit/acceptor [junit] 2009-10-20 21:38:03 net.jsunit.AbstractJsUnitServer logStatus [junit] 信息: Waiting for C:\Program Files\Internet Explorer\iexplore.exe to submit result [junit] 2009-10-20 21:38:11 com.opensymphony.xwork.interceptor.component.Com ponentInterceptor <clinit> [junit] 信息: WebWork's IoC has been deprecated, please use an alternative s uch as Spring [junit] 2009-10-20 21:38:11 net.jsunit.AbstractJsUnitServer logStatus [junit] 信息: Received submission [junit] 2009-10-20 21:38:12 net.jsunit.AbstractJsUnitServer logStatus [junit] 信息: Test Run Completed [junit] 2009-10-20 21:38:12 net.jsunit.AbstractJsUnitServer logStatus [junit] 信息: Stopping server [junit] 2009-10-20 21:38:12 org.mortbay.util.ThreadedServer$Acceptor run [junit] 信息: Stopping Acceptor ServerSocket[addr=0.0.0.0/0.0.0.0,port=0,loc alport=8080] [junit] 2009-10-20 21:38:12 org.mortbay.http.SocketListener stop [junit] 信息: Stopped SocketListener on 0.0.0.0:8080 [junit] 2009-10-20 21:38:12 org.mortbay.util.Container stop [junit] 信息: Stopped org.mortbay.jetty.servlet.ServletHandler@1d7ad1c [junit] 2009-10-20 21:38:13 org.mortbay.util.Container stop [junit] 信息: Stopped ServletHttpContext[/jsunit,/jsunit] [junit] 2009-10-20 21:38:13 org.mortbay.util.Container stop [junit] 信息: Stopped org.mortbay.http.HttpServer@1f6f0bf [junit] ------------- ---------------- --------------- [junit] [junit] Testcase: C:\Program Files\Internet Explorer\iexplore.exe took 13.95 3 sec BUILD SUCCESSFUL Total time: 14 seconds E:\jsunit2.2\jsunit>
运行后会在jsunit/logs目录下生成日志文件,如下图:
上图中的文件名由resultid 与 browserId 组成,前一个红框为resultid,后一个为浏览器ID(比如browserFileNames属性配置了多个浏览器时就会从0开始编号)。
日志文件采用JUnit结果同样的XML格式,所以像自动化JUnit测试集一样,可以用同样的转换很容易地加以处理。可以直接查看XML文件,也可以使用JsUnit内置的“displayer”servlet。
要使用“displayer”servlet,首先确保JsUnit服务器已经运行。如果未运行,只需运行start_server目标。一旦JsUnit服务器开始运行,打开你最喜欢的浏览器,指向localhost:8080/jsunit/displayer?id=×××&browserId=0,这里的×××是你想查看的结果日志的ID,后一个x为浏览器ID。如果你想看上面那个XML文件,可以在地址栏中输入 http://localhost:8080/jsunit/displayer?id=1256046869328&browserId=0 ,你会看到测试运行的结果,如下图所示。
如果想在分布式主机上运行测试集,需要使用distributed_test Ant任务。当然,必须在要用的每个远程主机上配置一个JsUnit服务器,并配置适当的测试和浏览器。运行distributed_test Ant任务会调用一个JUnit测试(net.jsunit.DistributedTest),它会进一步在配置中提供的每个远程主机上调用一个servlet。这个servlet运行的基于JUnit的测试与本地运行的测试(net.jsunit.StandaloneTest)是一样的。然后,会在远程主机上配置的浏览器中运行测试,结果发送回发起者。
能过调用远程注机上的测试,这样就可以测试任何操作系统与浏览器的组合,并且可以以命令行方式执行所有的测试用例,然后我们就可以更进一步将对于JS代码的自动测试集成到持续集成工具(CC、AntHill、etc.)之中了。
附上这二节所用到的测试页 jsunitTest.rar ,我是放在与 jsunit同一目录下测试。