JsUnit也有setUp()与tearDown(),不过现在作为函数,而不是方法;测试函数(而不是测试方法)分成多个测试页(而不是测试类);另外JsUnit提供了自己的基于HTML的测试运行工具。
JUnit |
JsUnit |
Test 类扩展 TestCase |
测试页包含 jsUnitCore.js |
测试方法 |
测试函数 |
Test 类 |
基于 HTML 的测试页 |
TestSuite |
基于 HTML 的测试集 |
多个测试运行工具 |
基于 HTML/JavaScript 的测试运行工具 |
setUp() 和 tearDown() 方法 |
setUp() 和 tearDown() 函数 |
在虚拟机中运行 |
在浏览器中运行 |
用 Java 编写 |
用 JavaScript 编写 |
对于JsUnit,起步很简单,只需从JsUnit网站(http://www.jsunit.net/ 或 直接进入http://sourceforge.net/projects/jsunit/files/ 在下载页面里还可以下载eclipse的jsunit插件 )下载JsUnit zip文件。 把这个压缩文件解开,会得到一个jsunit文件夹,可以把Web服务器放在这里,这样整个团队或者整个组织就能更容易地使用JsUnit。JsUnit的大部分“核心”都在jsunit/app目录中,在这里可以看到jsUnitCore.js、jsUnitTracer.js和jsUnitTestManager.js,另外还有其他一些文件。如果你想运行具体的JsUnit测试,可以使用testRunner.html来运行jsunit/tests目录中找到的任何测试页。
用JsUnit编写测试与用JUnit编写测试很相似。测试函数不能有任何参数,必须有一个前缀test ,例如testDateValidation()。测试函数包含在一个测试页(test page)中,这类似于JUnit中的一个Test类。测试页必须包含jsUnitCore.js 文件,解开JsUnit zip文件后,就会在jsunit/app目录中找到这个文件。包含这个JavaScript文件实际上就是把一个外部JavaScript文件增加到页面中;只需使用脚本元素<script language="JavaScript" src="jsUnitCore.js"></script> 来引用这个文件。
一般地,JsUnit会自动发现测试函数,就像JUnit会发现所有测试方法一样。不过,有些操作系统/浏览器不能合作。如果你发现不能如你所愿地发现测试函数,使用exposeTestFunctionNames() 方法就能解决这个问题。
assert([comment], booleanValue) assertTrue([comment], booleanValue) assertFalse([comment], booleanValue) assertEquals([comment], value1, value2) assertNotEquals([comment], value1, value2) assertNull([comment], value) assertNotNull([comment], value) assertUndefined([comment], value) assertNotUndefined([comment], value) assertNaN([comment], value) assertNotNaN([comment], value) fail(comment)
以上使用可以参考jsunit\tests\jsUnitAssertionTests.html
这个例子中有一个简单的函数,会让两个数相加,而且有两个测试:一个用于正整数的相加,另一个用于负整数相加。要测试这个函数,先创建一个简单的Web页面,其中包含了jsUnitCore.js文件与要测试的simpleJS.js文件。
simpleJS.js清单:
function addTwoNumbers(value1, value2) { return parseInt(value1) + parseInt(value2); }
简单的测试页smimpleTest.html清单:
<html> <head> <title>Test Page</title> <!-- 首先这里要导入核心文件jsUnitCore.js --> <script language="JavaScript" src="jsunit/app/jsUnitCore.js"></script> <!-- 要测试的js文件 --> <script language="JavaScript" src="simpleJS.js"></script> <script language="JavaScript"> //测试方式要以test开头,且不带有参数 function testValidArgs() { //与Junit一样使用断言来进行测试 assertEquals("2 + 2 is 4", 4, addTwoNumbers(2, 2)); } function testWithNegativeNumbers() { assertEquals("negative numbers: -2 + -2 is -4", -4, addTwoNumbers(-2, -2)); } </script> </head> <body> This is a simple test page for the simpleJS file. </body> </html>
测试结果:
可以看到,两个测试函数会自动被发现,而且通常都是这样。不过,如果打开测试页,点击Run之后什么也没有发生,可能就需要使用exposeTestFunctionNames(), 以确保JsUnit能找到你的测试,如下代码:
exposeTest.html清单:
<html> <head> <title>A Test Page With exposeTestFunctions</title> <script language="JavaScript" src="jsunit/app/jsUnitCore.js"></script> <script language="JavaScript" src="simpleJS.js"></script> <script language="JavaScript"> //不是标准的测试方法,因为没有以test开头 function validArgs() { assertEquals("2 + 2 is 4", 4, addTwoNumbers(2, 2)); } function withNegativeNumbers() { assertEquals("negative numbers: -2 + -2 is -4", -4, addTwoNumbers(-2, -2)); } //如果找不到测试方法或要测试的方法不是以标准的test开头时,使用如下方法进行手动指定 function exposeTestFunctionNames() { var tests = new Array(2); tests[0] = "validArgs"; tests[1] = "withNegativeNumbers"; return tests; } </script> </head> <body> This is a simple test page that uses exposeTestFunctionNames. </body> </html>
像JUnit一样,JsUnit也支持setUp()和tearDown()。JsUnit与JUnit有一点是一样的,即setUp()和tearDown()是可选的 ,而且setUp()会在每个测试之前调用 ,tearDown()会在每个测试之后调用 。在大量使用setUp()和tearDown()之前,需要了解JUnit与JsUnit中setUp()和tearDown()方法的实现有两个重要区别。在JUnit中,每次测试运行会导致创建Test类的一个新实例,这说明,声明的所有实例变量在下一次测试运行时会“重置”。不过,JsUnit有所不同,它不会为每次测试运行重新加载测试页,所以变量状态会在多次测试之间保留 。还有一个重要区别与测试顺序有关,使用JUnit的话,测试方法执行的顺序是不能保证的。在JsUnit中,测试会按测试页中声明的顺序执行测试方法,先从最上面的测试开始(注:但不要依赖于这种顺序)。
下面显示了一个相当复杂的例子,其中使用了setUp()和tearDown()方法。这里同样以前面创建的add方法为基础,但是这一次会增加一个表单。你要使用setUp()填写这个表单,然后使用tearDown()方法自行清空。
setUptearDownTest.html清单:
<html> <head> <title>Using setUp and tearDown</title> <script language="JavaScript" src="jsunit/app/jsUnitCore.js"></script> <script language="JavaScript" src="simpleJS.js"></script> <script language="JavaScript"> //在测试方法执行前执行 function setUp() { document.getElementById("value1").value = "2"; document.getElementById("value2").value = "2"; } function testValidArgs() { assertEquals("2 + 2 should equal 4", 4, addNumbers()); } function addNumbers() { var val1 = document.getElementById("value1").value; var val2 = document.getElementById("value2").value; return addTwoNumbers(val1, val2); } //在所有测试方法执行完后执行 function tearDown() { document.getElementById("value1").value = ""; document.getElementById("value2").value = ""; } </script> </head> <body> <form id="test"> <input type="text" size="3" id="value1"/> <input type="text" size="3" id="value2"/> <input type="button" value="Add" onclick="addNumbers()"/> </form> </body> </html>
JsUnit还包含另外一个特性:setUpPage()函数(一次性启动方法),这是JUnit中所没有的。setUpPage()函数只对每个测试页调用一次(注,在测试集不起作用,只能在测试页里使用),即在所有测试函数调用之前调用。现在,你可能已经发现,这里很适合完成预处理,特别是在运行测试之前如果需要向页面加载一些数据,setUpPage()函数就非常有用 。不同于setUp()和tearDown()函数的是,使用setUpPage()不只是把处理放在这个函数中就行了的,如果确实选择使用这个特性,还得要保证函数完成时要把setUpPageStatus变量设置为complete,这就告诉JsUnit可以继续,接下来可以执行测试页上的测试了,否则如果未设置或设置成另外的值时,代码执行为阻止,浏览器将处理等待状态。
下面再来看前面的simpleJS.js文件,再增加3个函数,补充更多的数学特性。在此包括减法、乘法和除法函数,如代如下所示。
simpleJS2.js清单:
function addTwoNumbers(value1, value2) { return parseInt(value1) + parseInt(value2); } function subtractTwoNumbers(value1, value2) { return parseInt(value1) - parseInt(value2); } function multiplyTwoNumbers(value1, value2) { return parseInt(value1) * parseInt(value2); } function divideTwoNumbers(value1, value2) { return parseInt(value1) / parseInt(value2); }
下面使用setUpPage()函数建立一些简单的测试数据,请注意函数最后一行,必须告诉JsUnit你已经建好了测试页。
setUpPageTest.html清单:
<html> <head> <title>Using setUpPage</title> <script language="JavaScript" src="jsunit/app/jsUnitCore.js"></script> <script language="JavaScript" src="simpleJS2.js"></script> <script language="JavaScript"> var arg1; var arg2; function setUpPage() { arg1 = 2; arg2 = 2; //完成后一定要设置这个,否则会进入阻塞状态 setUpPageStatus = "complete"; } function testAddValidArgs() { assertEquals("2 + 2 should equal 4", 4, addTwoNumbers(arg1, arg2)); } function testSubtractValidArgs() { assertEquals("2 - 2 should equal 0", 0, subtractTwoNumbers(arg1, arg2)); } function testMultiplyValidArgs() { assertEquals("2 * 2 should equal 4", 4, multiplyTwoNumbers(arg1, arg2)); } function testDivideValidArgs() { assertEquals("2 / 2 should equal 1", 1, divideTwoNumbers(arg1, arg2)); } </script> </head> <body> This is an example of using setUpPage. </body> </html>
有了一些测试页之后,你可能想把它们组织为测试集(test suite,也称测试套件),这与JUnit中的TestSuite很相似。测试集把不同的测试页分组组织,这样只需运行一个测试集就能一次运行类似的一组测试。测试集其实就是一些特殊的测试页,其中包含的测试页或其他测试集(相应地就有了一个主测试集)会按顺序运行。
可以采用定义测试页的方式来定义测试集,不过有两个例外。首先,测试集中不能包含任何测试函数 ;其次,你的测试集必须包含一个返回JsUnitTestSuite对象的suite()函数 。可以使用两个方法向测试集中增加测试页或子测试集:addTestPage(testPage) 和addTestSuite(testSuite)。 前者向测试集中增加单个的测试页;后者向测试集中增加另一个测试集。要记住,向测试集中增加一个测试页时,需要提供一个完全限定名,或者要提供测试页文件相对于测试运行工具的相对路径名。如果想向测试集中增加其他的测试集,要记住,提供给addTestSuite的参数类型必须为JsUnitTestSuite,它还要在suite函数所在的同一个页面中声明 。
testSuit.html清单:
<html> <head> <title>Sample Test Suite</title> <script language="JavaScript" src="jsunit/app/jsUnitCore.js"></script> <script language="JavaScript"> function sampleSuite() { var sampleSuite = new top.jsUnitTestSuite(); sampleSuite.addTestPage("../smimpleTest.html"); sampleSuite.addTestPage("../setUpPageTest.html"); sampleSuite.addTestPage("../setUptearDownTest.html"); return sampleSuite; } //测试集中一定要有以下这个方法 function suite() { var testSuite = new top.jsUnitTestSuite(); //如果想向测试集中增加其他的测试集,要记住,提供给addTestSuite的参数类 //型必须为JsUnitTestSuite,它还要在suite函数所在的同一个页面中声明。 testSuite.addTestSuite(sampleSuite()); testSuite.addTestPage("../exposeTest.html"); return testSuite; } </script> </head> <body> This is a simple test suite. </body> </html>
编写JavaScript时最困难的一部分就是跟踪代码。因为JavaScript不同于其他许多语言,没有一个得力的日志库来帮助你,因此无法以一种一致的方式打印语句,相反,你必须使用alert()。当然,alert()也不是不行,但它肯定不是最理想的方法。为了查找一个问题,要“沿路”布下一大堆alert()函数,这是很讨厌的,而且一旦修正了bug,还要再把这一大堆alert()代码统统去掉。当然,等你删除掉所有额外的alert()函数后,没准又会出现另一个bug,而且就出现在上一个bug的附近,这就要求你又得把所有alert()函数再加上。你现在应该知道,为什么没有多少人喜欢JavaScript了吧!
为了让JavaScript开发人员的日子更好过,JsUnit支持跟踪!JsUnit包含以下3个函数,任何测试都可以调用(注意,在每个函数中,value参数是可选的):
warn(message, [value])
inform(message, [value])
debug(message, [value])
JsUnit支持3个跟踪级别:warn(警告)、info(信息)和debug(调试)。运行测试时,要指定你想在哪个级别上输出。这3个级别按以下顺序层叠:warn, info, debug。这说明,如果运行测试时选择debug,就会看到warn()、inform()或debug()函数发出的所有消息。如果选择warn,则只会显示由warn()函数发出的消息,选择info则会显示由warn()和inform()发出的消息。默认值为no tracing(不跟踪)。下面向这个简单例子增加一些跟踪函数,来看看会发生什么。
testTrace.html清单:
<html> <head> <title>A Simple Test Page with Tracing</title> <script language="JavaScript" src="jsunit/app/jsUnitCore.js"></script> <script language="JavaScript"> function addTwoNumbers(value1, value2) { warn("this is a warning message"); warn("this is a warning message with a value", value1); return value1 + value2; } function testValidArgs() { inform("this is an inform message"); assertEquals("2 + 2 is 4", 4, addTwoNumbers(2, 2)); } function testWithNegativeNumbers() { debug("this is a debug message"); assertEquals("negative numbers: -2 + -2 is -4", -4, addTwoNumbers(-2, -2)); } </script> </head> <body> This is a simple test page for addTwoNumbers(value1, value2) with tracing. </body> </html>
要看跟踪函数得到的输出,需要在测试运行工具中启用跟踪,并选择适当的跟踪级别。如果选择debug,可以看到来自这3个函数的全部消息,“Close Old Trace Window on New Run”(下一次运行测试时关闭上一个跟踪窗口)复选框的作用是,如果你愿意,可以保留以前运行测试的跟踪结果。
你已经写了一些测试,下面需要运行它们,为此可以使用JsUnit测试运行工具。你已经看到启动测试运行工具的许多例子,不过这是怎么做到的呢?为了访问这个运行工具,要把浏览器指向jsunit文件夹中的testRunner.html文件。
这个测试运行工具非常类似于JUnit中常用的图形化运行工具。(不过,有意思的是,我们期盼已久的JUnit 4并没有包括图形测试运行工具,而且以后也不会增加。)要运行一个测试,可以点击Choose File(注,本来是有这个按钮的,在IE6上有,IE7上就显示不出来,在firefox3.5上也有,但在firefox3.5上好像不能运行起来),来选择要运行的文件。不出所料,在测试运行工具发现失败之前,进度条一直是绿的。Runs字段指示测试函数的总数,还可能报告错误或失败。
错误(error)来自浏览器,指示测试页出现了某个问题,失败(failure)指示你的某个断言失败。
特定的错误或失败会显示在Errors and Failures文本框中。要了解一个错误或失败的更详细的信息,可以双击相应测试函数。或者,选中这个测试函数,再选择Show Selected。如果是失败,就会出现一个警告,显示出期望值和实际值,另外还会显示你在断言中增加的所有消息。如果看到一个错误,相应的消息(可能)会帮助你缩小查找的范围,更快地找到问题所在。
下面再来看以下错误代码
errorTest.html代码清单:
<html> <head> <title>Using setUpPage</title> <script language="JavaScript" src="jsunit/app/jsUnitCore.js"></script> <script language="JavaScript" src="simpleJS2.js"></script> <script language="JavaScript"> var arg1; var arg2; function setUpPage() { arg1 = 2; arg2 = 2; setUpPageStatus = "complete"; } function testAddValidArgs() { //结果应该是4 assertEquals("2 + 2 should equal 4", 5, addTwoNumbers(arg1, arg2)); } function testSubtractValidArgs() { //无subtractTwoNumbers11111方法 assertEquals("2 - 2 should equal 0", 0, subtractTwoNumbers11111(arg1, arg2)); } function testMultiplyValidArgs() { assertEquals("2 * 2 should equal 4", 4, multiplyTwoNumbers(arg1, arg2)); } function testDivideValidArgs() { assertEquals("2 / 2 should equal 1", 1, divideTwoNumbers(arg1, arg2)); } </script> </head> <body> This is an example of using setUpPage. </body> </html>
运行结果如下:
双击列表框中的错误信息项或点击“Show all”,会显示错误的详细信息,如下图: