日期:2014-05-16  浏览次数:20322 次

Qunit整合seajs单元测试组件

? 前些天在项目中由于要用到单元测试,包装了一个基于seajs的Qunit单元测试框架,看了下Qunit的源码,发现Qunit直接支持CommonJs模式的封装:

?

如是,直接移植到seajs下

?

define(function(require, exports, module) {
	require('tests/qunit/qunit.css');
        //Qunit Code
});

?

? 接下去做基于需求的外层封装:

几个要求,要有直接控制台log功能,有多次注入测试功能:

如下进行封装(assert.js)

?

define(function(require, exports, module) {
	
	var $ = require('lib/jquery');
	var q = require('tests/qunit/qunit');
	//开启log
	var enableLog = function(){
		
		var logs = ["begin", "testStart", "testDone", "log", "moduleStart", "moduleDone", "done"];
		for (var i = 0; i < logs.length; i++) {
			(function() {
				var log = logs[i];
				q.QUnit[log] = function() {
					console.log(log, arguments);
				};
			})();
		}
		
	};
	
	var _test = function(conf){
		
		var settings = {};
		var defaults = {
			enableLog : false,
			unitTest : $.noop
		};
		settings = $.extend(true,{}, defaults, conf);
		
		if(settings.enableLog) {
			enableLog.call(this);
		}
		
		if(settings.unitTest) {
			if(!$.isArray(settings.unitTest)){
				settings.unitTest = [settings.unitTest];
			}
			for(var i = 0, len = settings.unitTest.length; i < len; ++i){
				settings.unitTest[i].call(this, q);
			}
		}
		
	};
	
	//一次性run
	exports.run = function(conf){
		q.QUnit.reset();
		_test.call(this, conf);
		q.QUnit.load();
	};

	//开启log
	exports.enableLog = enableLog;
	
	//注入前最好reset一下
	exports.reset = q.QUnit.reset;
	//多次注入testcase
	exports.test = _test;
	//注入case后要load一下
	exports.load = q.QUnit.load;
	
});
?

?

这样一个经过封装的assert断言module就好了。可以进行log输出进多次的单元测试注入。

?

接下来来一个分发(dispatch)module的单元测试案例:

?

组件的代码:

?

?

define(function(require, exports, module){
	var $ = require('lib/jquery');
	var _ = require('lib/underscore');
	var _url = '/notice/tips4web.json';
	var _parameter = {};
	var _timer = 60000;
	var events = [];
	var timeoutFlag = null;
	
	var _fire = function(data){
		for(var i=0,l=events.length;i<l;i++){
			try{
				events[i].fn(data, events[i].arg);
			}catch(e){
				continue;
			}
		}
		//log(events)
	};
	
	exports.update = function(op){
		_parameter = op;
	};
	
	exports.refresh = function(timer){

		_timer = timer || 60000;
		
		if(!!timeoutFlag){
			clearInterval(timeoutFlag);
		}
		
		var ajaxing = false;
		timeoutFlag = setInterval(function(){
			if(ajaxing){
				return;
			}
			ajaxing = true;
			$.ajax({
				global:false,
				url : _url,
				data : _parameter,
				_complete:function(){
					ajaxing = false;
				},
				_success:function(data){
					_fire(data);
				}
			});
		}, _timer);
		
	};

	exports.subscribe = function(fn,arg){
		var id = $.now();
		events.push({
			id:id,
			fn:fn,
			arg:arg
		});
		return id;
	};

	exports.unsubscribe = function(id){
		if(!events || !id){
			return false;
		}
		for(var i=0,l=events.length;i<l;i++){
			if(events[i].id === id){
				events.splice(i,1);
				return true;
			}
		}
		return false;
	};
	
	exports.clear = function(){
		_parameter = {};
		events = [];
	};
	
	exports.stop = function(){
		if(!!timeoutFlag){
			clearInterval(timeoutFlag);
		}
	};

	exports.fire = _fire;
	
});

?

?

这个组件是一个消息中间件:

?

下面我们测试的要点是测试接口可用性和异步通信的触发及销毁:

?

?

define(function(require, exports, module) {
	
	var assert = require('tests/qunit/assert');
	var $ = require('lib/jquery');
	var rm = require('module/reminder/reminder-middleware');
	
	var _unitTest = function(q){
		
		var isLogin = true;
		var ajaxing;
		
		q.module("reminder 接口测试");
		
		q.asyncTest("没有参数group时", function() {
			ajaxing = true;
			$.ajax({
				global:false,
				url:'/notice/tips4web.json',
				_comp