QUnit框架介绍
QUnit是jQuery团队开发的JavaScript单元测试工具,目前所有的JQuery代码都使用QUnit进行测试,并且JQuery开发团队将他们的使用QUnit写的测试代码都发布出来了,光凭这一点就足以QUnit的强大,足以胜任大部分JavaScript单元测试。
QUnit的优点:
- 使用起来非常方便,有漂亮的外观和完整的测试功能(包括异步测试),这是见过最漂亮最详细的测试界面了。
- 非常简单,容易上手,目前公开的APi只有16个。
- 不需要依赖其它任何软件包或框架,只要能运行JS的地方就可以,QUnit本身只有一个JS文件和CSS文件,当然如果需要可以和JQuery等其它框架集成。
- 不仅支持在浏览器中测试,还支持在Rhino和node.js等后端测试。
QUnit的缺点:
- 对自动化支持不好,很难和Ant/Maven或自动构建等工具集成,主要用在浏览器中进行测试。
QUnit环境配置
首先下载QUnit的开发包,解压后我们只需要qunit目录下的qunit.css和qunit.js文件即可。然后创建一个HTML文件将这两个文件引用进来即可,HTML代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>QUnit Test Suite</title>
<link rel="stylesheet" href="../qunit/qunit.css" type="text/css" media="screen">
<script type="text/javascript" src="../qunit/qunit.js"></script>
<script type="text/javascript" src="test.js"></script>
<script type="text/javascript" src="same.js"></script>
<script src="swarminject.js"></script>
</head>
<body>
<h1 id="qunit-header">QUnit Test Suite</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
<div id="qunit-fixture">test markup</div>
</body>
</html>
建议另外建两个和qunit同级的目录,src和test,分别用来放源代码和测试代码。然后把这些所有的代码都引入到上面的HTML文件中去。所有这些准备好后就可以享受QUnit单元测试的乐趣了。
QUnit使用方法
QUnit的用法比较简单,API不是很多,所有的API也就16个左右。所有的API可以分为三类:Setup,Assertions,Asynchronous Testing,下面就分别对这些API做些介绍,约定:凡是用[]包起来的参数表示可选参数。
Setup:
- test( name, [expected], test ),代表QUnit中的一个测试,就是没添加一个测试就调用一次test(),name参数是要测试的名称,比如”加法函数”或”add”等,expected参数是可选参数,用来表示该测试函数的断言的数量,是个正整数,test参数是一个函数对象,所有的测试代码都应该包括在该函数里,通常这是一个匿名函数。例如:test(“add function”, 1, function() {equal(add(1, 2), 3);});
- asyncTest( name, [expected], test ),代表QUnit中的一个异步测试,这个会在异步测试中,参数同上一个test( name, expected, test )
- expect( amount ),用在测试函数中,用于声明测试断言的数量,这个函数和test( name, expected, test )的expected参数的作用是一样的,两个用一个即可,当然都不用也没有关系。主要作用就是检查你声明的个数和你写的断言的实际个数是否一致。
- module( name, [lifecycle] ),这个函数主要用于测试函数的分组,你可以理解一个module函数是一个模块的意思,比如module(“validate”)表示后面的测试用例都是alidate相关的代码,或者module(“common.js”),表明后面的测试用例都是common.js里面的代码,如何划分看个人理解啦,一个测试文件是可以写多个module的。name参数是分组或者模块的名称,lifecycle是可选参数,它是一个对象类型,可以设置setup和teardown回调函数,例如module(“common.js”, {setup:function(){},teardown: function() {} }),setup回调函数将会在module开始之前执行,比如可以为该module下面的测试代码做一些准备工作,teardown回调函数将会在该module的所有测试代码执行后执行,比如做一些清理还原工作等。
- QUnit.init( ),用于初始化QUnit测试框架,通常这个函数是不需要我们手工调用的。
- QUnit.reset( ),重设函数,通常是在每个test函数执行后由QUnit自己调用来重设整个QUnit测试环境,当然必要时我们自己也可以调用它来复原,不过目前我还没有调用过它。
Assertions:
所有断言函数的message都是可选参数,可以是一段话来描述整个断言,这样在测试结果页面可以很清楚看出这个断言是干什么的,比如equal(add(1, 2), 3, “1加2应该等于3″)
- ok( state, [message] ),布尔断言,参数state的值为true时表示通过,否则失败。
- equal( actual, expected, [message] ),比较参数actual和expected是否相等,转化为JavaScript代码为if (actual == expected),是不比较类型的。
- notEqual( actual, expected, [message] ),比较两个参数不相等,转化为JavaScript代码为if (actual != expected),是不比较类型的,不相等则通过,否则失败。
- deepEqual( actual, expected, [message] ),主要用于数组和对象等类型的值是否相等,会递归遍历它们所包含的值是否相等。
- notDeepEqual( actual, expected, [message] ),主要用于数组和对象等类型的值是否不相等,会递归遍历它们所包含的值是否不相等。
- strictEqual( actual, expected, [message] ),比较参数actual和expected的值和类型是否相等,转化为JavaScript代码为if (actual === expected),是需要比较类型的。
- notStrictEqual( actual, expected, [message] ),比较参数actual和expected的值和类型是否不相等,转化为JavaScript代码为if (actual !== expected),是需要比较类型的。
- raises( block, expected, [message] ),测试block函数是否抛出一个异常,抛出则通过,不抛则失败。block参数是我们要测试的函数,expected参数是一个函数,是一个可选参数,用来验证第一个函数抛出的异常是否是我们想要的。
Asynchronous Testing:
- stop( [increment] ),停止测试的运行,因为在异步环境中,不停止的话就运行结束了,异步的回调都不会被处理,所以在异步测试时一般先把QUnit的test runner停下来。increment参数是增加停止的时间。
- start( [decrement] ),当异步调用成功后就应该把停止的test runner启动起来让它接着往前跑了,decrement参数用来减少停止的时间。
异步测试的代码需要写在asyncTest( name, [expected], test )中,一个Ajax异步测试的例子:
//Ajax调用函数
function ajax(successCallback) {
$.ajax({
url: 'ajxjserver.php',
success: successCallback
});
}
test('异步测试', function() {
// 暂停测试
stop();
ajax(function() {
// 异步调用测试代码
})
setTimeout(function() {
//异步测试完成后,恢复test runner,接着处理其他测试代码
start();
}, 3000);
})
与浏览器自动化测试工具集成的接口
QUnit额外提供了一些与浏览器自动化测试工具集成的接口,这些接口实现后会被QUnit自动调用,注意,这些接口是留着我们开发人员自己来实现的。这里简单做些介绍:
- QUnit.log({ result, actual, expected, message }),这个接口会在每个断言执行后调用,result值是断言是否通过,message是断言里的message参数。
- QUnit.testStart({ name }),在每个测试函数执行前调用,name参数是测试函数中的name参数值,这里的测试函数是指test()或者asyncTest()。
- QUnit.testDone({ name, failed, passed, total }),在每个测试函数结束后执行,name参数同上,failed参数是指失败断言的个数,passed参数是指成功断言的个数,total是指所有断言的个数。
- QUnit.moduleStart({ name }),在每个module后面所有的测试代码执行前调用,name参数是module(name)中name的值。
- QUnit.moduleDone({ name, failed, passed, total }),在module下面所有的测试代码执行完之后执行,failed参数是指失败断言的个数,passed参数是指成功断言的个数,total是指所有断言的个数。
- QUnit.begin(),在所有的测试代码调用之前运行。
- QUnit.done({ failed, passed, total, runtime }),在所有的测试代码调用之后运行,failed参数是指失败断言的个数,passed参数是指成功断言的个数,total是指所有断言的个数,runtime代码所有代码的执行时间。
除了学习如何使用QUnit外,QUnit的源代码也是非常不错的学习材料,源代码中除去第三方的代码,也就1000行左右的代码,而且代码写得非常好,建议多阅读它的代码,这样不仅可以学习如何更好些好Javasciprt代码,还可以加深对QUnit的理解。
另外可以多看一下JQuery核心代码的测试代码,看看JQuery开发团队是怎么写QUnit测试代码的,有助于提高我的单元测试水平。
更多关于JavaScript单元测试的教程
QUnit官方文档