nodejs学习笔记5

测试模块

选取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

编写测试

一般来说创建一个tests目录放置测试脚本,且每个要测试的模块都包含一个文件。首先获得test构造函数:

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=2t.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);
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值