JavaScript 测试框架 ( QUnit , javascript code coverage , JSCoverage , Pavlov , Jasmine )

changelist:

--------------------------------

1.0

如何利用QUnit来进行javascript的TDD


1.1

添加javascript code coverage

添加Pavlov介绍,如果利用Qunit进行BDD

--------------------------------

现下有很多JavaScript的测试框架,比如:Jasmine ,  Qunit等(后续会继续补充)

关于单元测试的TDD(Test  Drive Develop)框架,我觉得来自他人博客的一段话很好的说明了一些基本的需求:(参见:http://www.cnblogs.com/tonyqus/archive/2010/10/31/jquery_tdd_qunit.html

作为标准的TDD框架,必须满足这么几个要求:

1. 即使测试脚本出错了也要能继续运行接下来的脚本

2. 能够不依赖被测试代码写测试用例,即使代码没有实现也可以先写测试用例

3. 能够显示详细的错误信息和位置

4. 能够统计通过和未通过的用例的数量

5. 有专门的可视化界面用于统计和跟踪测试用例

6. 易于上手,通过一些简单的指导就可以马上开始写测试代码。

在这之中,个人觉得目前比较容易上手的有QUnit,那么首先说说Qunit。

Qunit 官方站点:http://docs.jquery.com/QUnit

如何使用Qunit?

首先去http://github.com/jquery/qunit 下载Qunit(包括 qunit.js 和 qunit.css)

之后,新建一个测试页面,标准的代码如下:

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="js/jquery-1.7.1.js"></script>
<link rel="stylesheet" href="js/qunit/qunit.css"/>
<script type="text/javascript" src="js/qunit/qunit.js"></script>
<!--测试代码-->
<script>
test("hello", function() {
    ok(true, "world");
});
</script>
  
</head>
<body>
 	 <h1 id="qunit-header">QUnit example</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, will be hidden</div>
</body>
</html>

在浏览器中看的效果如图:



更通常的写法,在页面中加入一个单独的js引用专门用来写单元测试的function,比如叫test.js

<script language="javascript" src="test.js" type="text/javascript"/>


test.js的内容来自 http://msdn.microsoft.com/en-us/scriptjunkie/gg749824

function format(string, values) {
    for (var key in values) {
        string = string.replace(new RegExp("\{" + key + "}"), values[key]);
    }
    return string;
}
 
test("basics", function() {
    var values = {
        name: "World"
    };
    equal( format("Hello, {name}", values), "Hello, World", "single use" );
    equal( format("Hello, {name}, how is {name} today?", values),
        "Hello, World, how is World today?", "multiple" );
});



在浏览器中,我们看到如下的效果:

这就是一个标准的QUnit的测试界面,红色的表示这个测试用例没有通过,绿色的表示通过。每一个框比表示一个测试函数,里面可能有多个断言语句的结果,标题中(x,y,z)表示总共有z个断言,y个是正确的,x个是错误的。

在Qunit中,经常用到的函数有:

expect(amount) - 指定某个函数中会有多少个断言,通常写在测试函数开头。

module(name) - 模块是测试函数的集合,使用该函数可以在UI中将测试函数按模块归类。

ok(state, message) – 布尔型断言,message是专门显示在QUnit界面上,用来区分不同的断言的

equals(actual, expected, message) - 相等断言,actual和expected的值相等时才能通过。

这些是最常用的,其他的大家可以自己参考Qunit官方文档。

另外,有些测试中,我们如果改变DOM,那么这样跑完一个测试用例,就会影响到下一个测试用例,这样的情况怎么办呢?其实QUnit已经考虑到了这一点,只要我们把需要修改的内容放在"qunit-fixture" 这个div的里面, 在运行下一个测试用例之前,QUnit会先自动reset 这个div里面的内容,这样测试用例就不会互相干扰。

<div id="qunit-fixture">
    <input id="input" type="text" placeholder="placeholder text" />
</div>


另外,如果还有一些额外的数据需要操作的话,QUnit也提供了module的概念,类似于测试用例组。
module("core", {
    setup: function() {
        // runs before each test
    },
    teardown: function() {
        // runs after each test
    }
});
test("basics", function() {
    // test something
});

这样在每次执行test的时候,都会先执行一次setup函数,再执行完test的时候,会执行teardown函数。


上面的测试都是同步的,就是说一旦载入测试页面,就会开始跑测试用例,那么又如何测试ajax等需要回调的异步操作呢?QUnit也考虑到了这一点,

提供了三个函数,start, stop , asyncTest.

function ajax(callback){
	$.ajax({
		url:"/ajaxtest",
		success:callback
	});
}

test("asynchronous test" , function(){
	stop();
	
	expect(3);
	
	ajax(function(){
		ok(true);
	});

	ajax(function(){
		ok(true);
		ok(true);		
	});
	
	setTimeout(function(){
		start();
	},1000);
});


asyncTest("asynchronous test" , function(){	
	expect(3);
	
	ajax(function(){
		ok(true);
	});

	ajax(function(){
		ok(true);
		ok(true);		
	});
	
	setTimeout(function(){
		start();
	},1000);
});

asyncTest已经调用了一次stop,所以不需要像test一样再调用一次stop函数。

很多的时候,在写代码的时候,服务器端还没有写好,那么这个时候,往往需要去模拟ajax的请求,那么在这样的情况下,又该如何呢?这个时候可以借助于jquery.mockjax.js,官网:https://github.com/appendto/jquery-mockjax , 这个插件很方便使用,只要在代码中引入jquery.mockjax.js,同时加上需要模拟的ajax的请求就可以了,下面是一个例子:

$.mockjax({
	  url: '/ajaxtest',
	  responseTime: 200,
	  responseText: {
	    status: 'success',
	    fortune: 'Are you a turtle?'
	  }
});


另外对于需要模拟鼠标,键盘操作的,可以用jquery的trigger(比如:trigger($.Event("keydown", { which: 40 }));), 也可以用YUI的UserAction。

如果进行javascript code coverage?

上面一直再讲如何用Qunit来写单元测试,但是很多的时候单元测试是要看覆盖率的。那么在javascript里面怎么做coverage测试呢?

在这里介绍一个专门用于javascript coverage的工具:JSCoverage (官网:http://siliconforks.com/jscoverage/

先看看和Qunit结合的效果:

再看看coverage的效果:

再看看代码中有哪些没有覆盖:(红色的地方没有覆盖,绿色的地方覆盖)

效果看完了,那是怎么把JSCoverage和QUnit结合起来使用呢?

1》安装JSCoverage

2》新建两个目录(目录名随意),一个叫source,一个叫dest。把需要测试的js文件(例如:XX.js)放在一个目录中(例如,目录名为source)

3》运行jscoverage source dest

4》这样在dest中,就会把XX.js格式化一下,同时也会生成jscoverage.html,jscoverage.css和jscoverage.js等和jscoverage相关的文件。

5》用jscoverage生成的XX.js替换掉原先的xx.js,同时把jscoverage.html,jscoverage.css和jscoverage.js等文件拷贝到相关的目录

6》在浏览器中运行jscoverage.html?xxx.html(xxx.html是用qunit写好的测试代码)

那么JSCoverage是怎么做到的呢?

原来在我们需要测试的代码的开始的地方,声明了一个对象,这个对象通过行号来表示每一行跑过还是没有跑过

if (! _$jscoverage['enginecore.js']) {
  _$jscoverage['enginecore.js'] = [];
  _$jscoverage['enginecore.js'][1] = 0;
  _$jscoverage['enginecore.js'][16] = 0;
  _$jscoverage['enginecore.js'][17] = 0;
  _$jscoverage['enginecore.js'][18] = 0;
  _$jscoverage['enginecore.js'][20] = 0;
  _$jscoverage['enginecore.js'][23] = 0;
  _$jscoverage['enginecore.js'][24] = 0;
  _$jscoverage['enginecore.js'][26] = 0;
  _$jscoverage['enginecore.js'][27] = 0;

在一个方法中,我们可以看到,对应的代码一旦跑过,在代码开始声明的对象就会记录下来。

ui.engine.ButtonBar.prototype._setItemToHighlightState = (function (index) {
  _$jscoverage['enginecore.js'][1463]++;
  var buttonBar = this;
  _$jscoverage['enginecore.js'][1465]++;
  var item = buttonBar._getItem(index);
  _$jscoverage['enginecore.js'][1466]++;
  var button = buttonBar._getButton(index);
  _$jscoverage['enginecore.js'][1467]++;
  item.find(">img").attr("src", button.icon.highlight);
});

参考资料:

Qunit:

1》http://msdn.microsoft.com/en-us/scriptjunkie/gg749824

2》http://www.cnblogs.com/tonyqus/archive/2010/10/31/jquery_tdd_qunit.html

3》http://hetao.im/2011/03/13/%E9%87%87%E7%94%A8tdd%E8%BF%9B%E8%A1%8Cjavascript%E5%BC%80%E5%8F%91

4》http://www.groovyq.net/content/qunit%E5%B0%8F%E8%AE%B0

5》http://www.oncoding.cn/2010/javascript-unit-testing-qunit/

6》http://yue.st/slides/gktest/

7》http://lds2008.blogbus.com/tag/qunit/ 

8》http://www.weakweb.com/articles/category/javascript%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95

JSCoverage:

http://siliconforks.com/jscoverage/manual.html

JSCoverage & Qunit:

http://www.eviltester.com/index.php/2008/06/08/test-driven-javascript-code-coverage-using-jscoverage/

http://msdn.microsoft.com/zh-tw/scriptjunkie/ff452703.aspx (写到这里,居然发现有了一篇很类似的文章)













  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值