当前位置: 代码迷 >> JavaScript >> Qunit调整seajs单元测试组件
  详细解决方案

Qunit调整seajs单元测试组件

热度:173   发布时间:2012-09-04 14:19:30.0
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',
				_complete:function(){
					ajaxing = false;
				},
				_success:function(data){
					q.equal( typeof(data['storyCount']) , 'undefined', '期望:"storyCount"未定义' );
					q.ok(true, "数据返回成功");
					q.start();
				},
				_failure: function(errors){
					var errorInfo = errors[0].msg;
					q.ok(false, errorInfo);
					q.start();
				}
			});
		});

		q.asyncTest("主墙reminder", function() {
			ajaxing = true;
			$.ajax({
				global:false,
				url:'/notice/tips4web.json',
				data : {'group': 'main'},
				_complete:function(){
					ajaxing = false;
				},
				_success:function(data){
					q.notEqual( typeof(data['storyCount']) , 'undefined', '期望:"storyCount"有定义' );
					if(typeof(data['storyCount']) !== 'undefined'){
						q.ok(true, "数据返回成功");
						q.start();
					}
				},
				_failure: function(errors){
					var errorInfo = errors[0].msg;
					q.ok(false, errorInfo);
					q.start();
				}
			});
		});
		
		q.asyncTest("有人说reminder", function() {
			ajaxing = true;
			$.ajax({
				global:false,
				url:'/notice/tips4web.json',
				data : {'group': 'incoming'},
				_complete:function(){
					ajaxing = false;
				},
				_success:function(data){
					q.notEqual( typeof(data['storyCount']) , 'undefined', '期望:"storyCount"有定义' );
					if(typeof(data['storyCount']) !== 'undefined'){
						q.ok(true, "数据返回成功");
						q.start();
					}
				}
			});
		});

		q.module("reminder 触发器测试");
		
		var rid = null;
		
		var _doSuccess = function(data){
			q.ok(true, "数据返回成功");
			q.start();
		};

		q.asyncTest("触发器创建并刷新", function() {

			rid = rm.subscribe(function(data, arg){
				_doSuccess.call(this, data);
				rm.stop();
				q.test('注销触发器',function(){
					q.ok(rm.unsubscribe(rid),'注销触发器成功');
					_updateTest.call(this, q);
				});
			},{});
			
			rm.refresh(1000);
			
		});

	};
	
	var _updateTest = function(q){
		
		q.module("reminder 触发器消息装换测试");
		
		var rmid = null;
		var isFirst = true;
		
		var _doReminderSuccess = function(data){
			if(isFirst){
				q.equal( typeof(data['storyCount']) , 'undefined', '没有参数时,期望:"storyCount"未定义' );
				q.ok(true, "数据返回成功");
				rm.update({'group': 'incoming'});
				isFirst = false;
				q.ok(rm.unsubscribe(rmid),'注销触发器成功');
				q.start();
				q.asyncTest("触发器URL更新并fetch", function() {

					rmid = rm.subscribe(function(data, arg){
						_doReminderSuccess.call(this, data);
					},{});
					
				});
			}else{
				q.notEqual( typeof(data['storyCount']) , 'undefined', 'Update为 incoming后,期望:"storyCount"有定义' );
				q.ok(true, "数据返回成功");
				rm.stop();
				q.start();
			}
			
		};
		
		q.asyncTest("触发器创建并刷新", function() {

			rmid = rm.subscribe(function(data, arg){
				_doReminderSuccess.call(this, data);
			},{});
			
			rm.refresh(1000);
			
		});
	};
	
	exports.run = function(conf){
		
		//开启log
		assert.enableLog();
		
		//直接run一个test,run只能出现一次,建议全部封装到unitTest中再一次性调用,适合单个调用
		
		assert.run({
			unitTest : _unitTest
		});

	};
});

?

最终效果:


?

最后还有一个问题:对于接口本地化测试会有跨域的问题,由于只是接口测试,不涉及兼容性,所以我们可以只用chrome测试,比较简单的跨域访问模式就是修改chrome的启动参数:

加上:

?

--disable-web-security

当然可以直接用bat文件写入:

?

CD C:\Documents and Settings\User\Local Settings\Application Data\Google\Chrome\Application
chrome.exe --disable-web-security
exit
?

?