[译] Cookbook of QUnit
本篇文章是QUnit的简介,可以作为很好的入门教程。文章原址
介绍
自动化测试时软件开发过程中必不可少的一部分,而单元测试则是自动化测试的最为基本的一块,软件的每一个组件,
每一个功能单元都需要经过不停地测试以保证在上线时可以正常的工作。当然,测试也不仅仅只有这些作用,最为人
所知的就是测试驱动设计(test-driven design),测试先于实现进行。先写出一个简单的测试,当然此时运行肯定会
出错,然后我们在开始完成具体的实现,直到测试通过。如果仅仅依靠我们自己实现测试函数,不仅仅难以抓住测试过程
中的各种细节(错误代码,错误位置,执行结果与预期结果差异),而且各个浏览器的兼容性也会让我们抓狂,所以我们
亟需一个解决浏览器差异性和提供详细信息的测试框架,John Resig大神写出了QUnit框架。我等凡人尽管写不出这种富有
调整型的框架,但是很有必要学会使用QUnit。
自动化单元测试
问题
我们想对应用进行单元测试,或者也想从测试驱动设计获益,此时我们需要自己手动写测试函数。但是正如上文所提,测试
细节信息和浏览器兼容性我们难以搞定,我们需要解决它。
解决方案
我们可以使用QUnit,在使用QUnit钱,需要引入qunit.js和qunit.css文件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>QUnit basic example</title>
<link rel="stylesheet" href="//code.jquery.com/qunit/qunit-1.16.0.css">
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<script src="//code.jquery.com/qunit/qunit-1.16.0.js"></script>
<script>
QUnit.test( "a basic test example", function( assert ) {
var value = "hello";
assert.equal( value, "hello", "We expect value to be hello" );
});
</script>
</body>
</html>
id为qunit-fixture的div标签是必须的,在所有的QUnit测试中都是一样,它是测试夹具。每次测试完都会讲测试夹具内的
内容清空。
我们可以发现并没有在显示的在documentReady之后执行测试,这是因为测试器将会控制测试的开始执行时间,在执行QUnit.test
时,将函数添加到一个等待队列中,知道测试器调用。
断言结果
问题
断言是单元测试必不可少的要素之一。使用者需要将预期的结果和让测试器执行具体实现的结果进行比对,并得出相应
的判断。
方案
QUnit提供了简单的断言。
ok( truthy [, message ] )
最基本的断言就是ok(),它必须提供一个boolean参数(或者可以转化为boolean的参数,在js中貌似都可以类型转换为boolean),
另外一个参数可选。
QUnit.test( "ok test", function( assert ) {
assert.ok( true, "true succeeds" );
assert.ok( "non-empty", "non-empty string succeeds" );
assert.ok( false, "false fails" );
assert.ok( 0, "0 fails" );
assert.ok( NaN, "NaN fails" );
assert.ok( "", "empty string fails" );
assert.ok( null, "null fails" );
assert.ok( undefined, "undefined fails" );
});
equal( actual, expected [, message ] )
equal用“==”操作符来比较actual和expected参数,message为测试通过显示的信息。
QUnit.test( "equal test", function( assert ) {
assert.equal( 0, 0, "Zero, Zero; equal succeeds" );
assert.equal( "", 0, "Empty, Zero; equal succeeds" );
assert.equal( "", "", "Empty, Empty; equal succeeds" );
assert.equal( 0, false, "Zero, false; equal succeeds" );
assert.equal( "three", 3, "Three, 3; equal fails" );
assert.equal( null, false, "null, false; equal fails" );
});
strictEqual()用“===”比较两个参数。
deepEqual( actual, expected [, message ] )
该方法对简单的数值类型也是使用“===”进行比较。而对于对象,则不是使用“===”。它会便利对象的属性,并比较键值对。
(键和值都会比较)。
QUnit.test( "deepEqual test", function( assert ) {
var obj = { foo: "bar" };
assert.deepEqual( obj, { foo: "bar" }, "Two objects can be the same in value" );
});
同步回调
问题
在回调模式中,放在回调函数中的代码可能会阻止断言执行,所以需要通过某种方式提醒断言是否执行。
方案
我们可以使用assert.expect(n)来设定预期执行断言的数量。如果没有执行预期数量的断言,将会报错。
QUnit.test( "a test", function( assert ) {
assert.expect( 2 );
function calc( x, operation ) {
return operation( x );
}
var result = calc( 2, function( x ) {
assert.ok( true, "calc() calls operation function" );
return x * x;
});
assert.equal( result, 4, "2 square equals 4" );
});
异步回调
问题
异步回调与测试器的队列和运行测试的方式有冲突。在该测试之后的测试函数将不会被执行。
方案
在异步回调中使用assert之后,调用assert.aysnc(),他会返回一个done函数,在测试执行完毕调用done函数。
经过测试,如果不调用done函数,则末尾切片函数将不会被执行,之后的测试函数也不会被执行。
QUnit.test( "asynchronous test: async input focus", function( assert ) {
var done = assert.async();
var input = $( "#test-input" ).focus();
setTimeout(function() {
assert.equal( document.activeElement, input[0], "Input was focused" );
done();
});
});
测试的原子性
在每次执行test之后,QUnit都会重置 #qunit-fixture的dom div,包括在内的事件。只要测试代码在测试夹具内,不用
手动对夹具进行清理。
组测试
组测试可以保证逻辑类似的测试在一起执行,而且可以添加切片函数。该函数在测试之前和之后执行。
QUnit.module( "module", {
setup: function( assert ) {
assert.ok( true, "one extra assert per test" );
}, teardown: function( assert ) {
assert.ok( true, "and one extra assert after each test" );
}
});
QUnit.test( "test with setup and teardown", function() {
assert.expect( 2 );
});
- 隐藏在Chrome插件商店中的恶魔——恶意插件User-Agent Swither分析
- 如何使用CDSW在CDH中分布式运行所有R代码
- 如何在CDH中使用HBase快照
- 中间件安全-Tomcat安全测试概要
- 如何在CDH集群使用HDFS快照
- Sentry赋予server1权限给hive以外用户时ACL不同步问题分析
- 如何使用Java连接Kerberos的HBase
- 香香的xss小记录(一)
- UAF Writeup - pwnable.kr
- 如何使用Nginx实现Impala负载均衡
- pwnhub年前最后一战——“血月归来”writeup
- MHN中心服务器搭建与树莓派蜜罐部署
- 如何在CDH中启用Spark Thrift
- 让你的以太坊 DApps 盈利的 6 种方法
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- koa2实现微信公众号关注自动回复消息
- 两个字数字字符串求和
- 设计模式(二):Android 源码中的工厂模式
- MoveIt!之ROS1Melodic版本发布(MoveItCpp教程)
- 机器学习第1天:线性回归(代码篇)
- PHP二分查找
- OnClick 的另一种书写
- JVM系列之:JIT中的Virtual Call
- 速读原著-UnixLinux基础(五)
- Celery在Django中的简单应用
- 基于数据库Binlog 的业务系统操作日志实现方案(阿里中间件Canal)
- 速读原著-UnixLinux基础(三)
- 手撸实现UDP和TCP通信
- 3分钟短文 | PHP获取函数参数名,和类定义的常量,都要反射!
- 3分钟短文 | Laravel模型获取最后一条插入记录的ID编号