选取node中的node-tap工具进行异步测试。
将node-tap包含进package.json文件的dev-dependencies就可安装它:
{
"name":"myApp",
"version":"0.1.0",
"devDependencies"{
"tap":"*"
}
}
然后执行命令:npm install
注:devDependencies属性是声明只用于开发和测试应用程序的依赖模块。
当在产品模式下安装应用程序时,可以使用-production选项跳过安装devDependencies所列的模块。
npm install -production
var test = require('tap').test;
//定义一个测试。传入测试名和一个包含测试代码的函数
test("addtion of 2 and 2 works",function(t){
t.equal(2+2,4,"2+2 should be 4");
t.end();
});
参数t包含面向测试的控制对象。利用该对象可以测试是否符合你的期望。并结束当前测试。
运行测试:node my_test.js.即可得到结果
使用断言测试模块
导入assert模块:
var assert = require('assert');
var a = true;
assert(a);
//可以传入一个消息来在测试失败时提供更多的显示信息
assert(a,"a should be truthy");
//相当于js的“==”操作符
assert.equal('10',10,'should be equal');
//相当于js的“===”操作符
assert.strictEqual('10',10,'string 10 should be equas to number 10');
assert.notEqual('10',10,'should be equal');
assert.notStrictEqual('10',10,'string 10 should be equas to number 10');
每一个断言函数都会设置一个期望条件,如果期望条件不满足则会抛出一个异常。
如果想测试两个对象,则这两个对象的引用必须指向同一个对象才会相等。
assert.equal({a:1},{a:1});//抛出异常
如果想比较对象的属性,就要用到深比较:
var obj = {b:1,a:[1,2,3]};
assert.deepEqual(obj,{a:[1,2,3],b:1});//不会抛出异常
deepEqual函数验证的仅仅是对象的可枚举属性。如果两个对象具有不同的原型,但是他们的所有可枚举属性相同,他们就不会表现出不同。
使用node-tap中的内置断言函数
用它来代替Node核心模块中的断言函数可好处是:可以查看测试计数,错误报告,合计报告等。
test('truthyness of numbers',function(t){
//测试值是否为真
t.ok(1,'1 should be truthy');
//测试值是否为假
t.notOk(0,'0 should not be truthy');
t.end();
});
//t.equal函数测试严格相等性或浅相等性:
test('sum works',function(t){
var a = 2=2;
t.equal(a,'4','2+2 should be 4');//断言失效
t.notEqual(a,4,'2+2 should not be 4');
t.end();
});
//等价性测试
test('object equivalency',function(t){
var a = {a:1,b:2};
t.equivalent(a,{b:2,a:1});
t.end();
});
//判断一个对象是否包含一系列属性
test('object similarity',function(t){
var a = {a:1,b:2};
t.similar(a,{a:1});
t.end();
});
//测试对象类型
test('object type',function(t){
t.type(1,"number");
t.end();
})
可以使用ASYNC控制库来控制回调流程。首先安装async模块:
npm install async.
下面实现一个给定数值平方的HTTP服务器。
var port = 8080;
require('http').createServer(function(req,res){
var body = "";
req.setEncoding('utf8');
req.on('data',function(data){
body += data;
});
req.once('end',function(){
var number = JSON.parse(body);
var squared = Math.pow(number,2);
res.end(JSON.stringify(squared));
});
}).listen(port,function(){
console.log('squaring server listening on port 8080');
});
串行执行
可以利用async.series函数将两个I/O操作串接起来。
var async = require('async'),
request = require('request');
function done(err,results){
if(err){throw err;}
console.log('results:%j',results);
}
async.series({
function(next){
request.post({uri:'http://localhost:8080',body:'4'},
function(err,res,body){
next(err,body && JSON.parse(body));
}
);
},
function(next){
request.post({uri:'http://localhost:8080',body:'5'},
function(err,res,body){
next(err,body && JSON.parse(body));
}
);
}
},done);
所有函数都结束后,会调用回调函数done,此时done函数带有每个回调函数的异步结果。以上执行后的结果为:results:[16,25].
并发执行
只要将上述例子的async.series改为async.parallel即可并发执行回调函数。
连续传递
如果下一个回调函数的执行取决于前一个回调函数结果。就可使用async.waterfall函数。
function done(err,res,body){
if(err){throw err;}
console.log('3^4=%d',body);
}
async.waterfall([
function(next){
request.post({uri:'http://localhost:8080',body:'3'},next);
},
function(res,body,next){
request.post({uri:'http://localhost:8080',body:body},next);
}
],done);
排队
控制在给定时刻同时存在的正在进行作业的最大数量就可使用async.queue函数。该函数创建一个队列,基于一个函数处理其中的元素。队列的客户端将作业和并发的最大数量传入这个函数,按照顺序执行每个作业。
function done(err,results){
if(err){throw err;}
console.log('results:%j',results);
};
var maximumConcurrency = 5;
function worker(task,callback){
request.post({uri:'http://localhost:8080',body:JSON.stringify(task)},
function(err,res,body){
callback(err,body && JSON.parse(body));
}
);
}
var queue = async.queue(worker,maximumConcurrency);
[1,2,3,4,5,6,7,8,9,10].forEach(function(i){
queue.push(i,function(err,result){
if(err){throw err;}
console.log(i+'^2=%d',result);
});
});
队列被创建之后可以修改最大并发数:
queue.concurrency = 10;
当队列达到最大并发数时,可以将一个函数赋给队列的saturated属性来监听:
queue.saturated = function(){
console.log('queue is saturated');
};
//也可以监听empty事件
queue.empty = function(){
console.log('queue is empty');
};
//当返回作业的最后一项作业时,队列会发射drain事件
queue.drain = function(){
console.log('queue is drained, no more work');
};
迭代
var results = {};
function done(err){
if(err){throw err;}
console.log('done!results:%j',results);
}
var collection = [1,2,3,4];
function iterator(value,callback){
request.post({
uri:'http://localhost:8080',
body:JSON.stringify(value)
},
function(err,res,body){
if(err) return callback(err);
results[value] = JSON.parse(body);
callback();
});
}
async.forEach(collectino,iterator,done);
当在所有元素完成了异步迭代之后,就会调用最后一个函数,即done。
如果向同步迭代可以使用async.forEachSeries(collection,iterator,done)函数。
如果向在异步迭代时控制最大并发数,可以使用async.forEachLimit():
var maximumConcurrency = 5;
async.forEachLimit(collection,maximumConcurrency,iterator,done);
映射
function done(err,results){
if(err){throw err;}
console.log('done!results:%j',results);
}
var collection = [1,2,3,4];
function iterator(value,callback){
request.post({
uri:'http://localhost:8080',
body:JSON.stringify(value)
},
function(err,res,body){
callback(err,body&&JSON.parse(body));
});
}
async.map(collection,iterator,done);
async.map()函数将每个结果传递给迭代函数中的回调函数,获得所有结果后按照正确的顺序将结果提交给done函数。
规约
与javascript的array.reduce()函数类似,不过他是异步执行的。
var collection = [1,2,3,4];
function done(err,results){
if(err){throw err;}
console.log('the sum of the squares of %j is %d',collection,results);
}
function iterator(memo,item,callback){
request.post({
uri:'http://localhost:8080',
body:JSON.stringify(item)
},
function(err,res,body){
callback(err,body&&(memo+JSON.parse(body)));
});
}
//第二个参数为初始值。然后在集合上的每个集合迭代,当一次迭代结束时,就将一个新的memo值传入回调函数,再加上memo原来的值
async.reduce(collection,0,iterator,done);
过滤
在js中可以对基于一个函数对集合进行过滤。async.filter可以异步执行相同的操作。
var collection = [1,2,3,4,5];
function done(result){
console.log('these are the elements whose square value is greater than 10:%j',result);
}
function test(value){
return value>10;
}
function filter(item,callback){
request.post({
uri:'http://localhost:8080',
body:JSON.stringify(item)
},
function(err,res,body){
callback(body && test(JSON.parse(body)));
});
}
async.filter(collection,filter,done);
还有一个与filter作用相反的函数:
async.reject(collection,filter,done);
检测
当满足某个条件时,想停止迭代。例如检测集合中第一个平方大于10的数。
var collection = [1,2,3,4,5];
function done(result){
console.log('the firsr element whose square value is greater than 10:%j',result);
}
function test(value){
return value>10;
}
function detect(item,callback){
request.post({
uri:'http://localhost:8080',
body:JSON.stringify(item)
},
function(err,res,body){
callback(body && test(JSON.parse(body)));
});
}
async.detect(collection,detect,done);
//可以使用detect的串行版本
async.detectSeries(collection,detect,done);
因篇幅问题不能全部显示,请点此查看更多更全内容