nodejs非导出方法测试
nodejs写模块的时候经常会有一些函数,我们是不需要导出的,但是为了保证程序的正常,还是需要对它进行测试的,比如下面的一个模块
var sum = function(nums) {
return nums.reduce(function(a, b) {
return a + b
})
}
module.exports = {
doit: function(nums) {
return sum(nums)
}
}
其中的doit
是导出的一个方法,mocha的测试代码如下:
var doit = require('./t.js').doit
var should = require('should')
describe('test', function() {
it('doit should return array sum', function() {
should(doit([1, 2, 3])).be.exactly(6)
})
})
如果我们想直接测试sum
函数怎么办?有两种方法
在test
环境时,导出到一个特定的对象上
var sum = function(nums) {
return nums.reduce(function(a, b) {
return a + b
})
}
module.exports = {
doit: function(nums) {
return sum(nums)
}
}
if (process.env.NODE_ENV === 'test') {
module.exports._private = {
sum: sum
}
}
测试的代码修改如下:
var doit = require('./t.js').doit
var should = require('should')
describe('test', function() {
it('doit should return array sum', function() {
should(doit([1, 2, 3])).be.exactly(6)
})
if (process.env.NODE_ENV === 'test') {
var sum = require('./t.js')._private.sum
it('sum should return array sum', function() {
should(sum([1, 2, 3])).be.exactly(6)
})
}
})
运行测试的时候,指明node的环境变量就行了NODE_ENV=test mocha s.spec.js
运行结果如下图:
使用rewire模块
rewire可以帮助我们修改和使用模块内非导出的变量及方法,比如上面的测试用例可以修改为:
var should = require('should')
var rewire = require('rewire')
var myModule = rewire('./t.js')
describe('test', function() {
it('doit should return array sum', function() {
should(myModule.doit([1, 2, 3])).be.exactly(6)
})
it('sum should return array sum', function() {
should(myModule.__get__('sum')([1, 2, 3])).be.exactly(6)
})
})
可以看到我们使用rewire包装过的模块,它有__set__
和__get__
方法,使用get就可以取到对应的方法进行测试,当然也可以进行一些mock
比如:
var should = require('should')
var rewire = require('rewire')
var myModule = rewire('./t.js')
myModule.__set__('sum', function(arry) {
return 0
})
describe('test', function() {
it('doit should return 0 while sum had reset ', function() {
should(myModule.doit([1, 2, 3])).be.exactly(0)
})
})
总结及分析
第一种方法算是一个约定,第二种方法更直接更彻底,推荐使用rewire的方式
作为一个有追求的程序员,了解一下rewire的原理还是相当有必要的
本质上rewire是把传入的js源码加工了一下,附加了一些代码,可以看这里
https://github.com/jhnns/rewire/blob/master/lib/rewire.js#L46
appendix = "\n";
appendix += "module.exports.__set__ = " + __set__Src + "; ";
appendix += "module.exports.__get__ = " + __get__Src + "; ";
appendix += "module.exports.__with__ = " + __with_Src + "; ";
// Check if the module uses the strict mode.
// If so we must ensure that "use strict"; stays at the beginning of the module.
src = fs.readFileSync(targetPath, "utf8");
if (detectStrictMode(src) === true) {
prelude = ' "use strict"; ' + prelude;
}
moduleEnv.inject(prelude, appendix);
moduleEnv.load(targetModule);
比如__get__方法
,通过eval
实现的, https://github.com/jhnns/rewire/blob/master/lib/__get__.js#L15
另外发现module里面很多没有在文档上写出来啊,比如https://github.com/jhnns/rewire/blob/master/lib/moduleEnv.js#L7 这里的wrapper,http://nodejs.org/api/modules.html 文档上啥也没有,只有看node的源码https://github.com/joyent/node/blob/master/lib/module.js#L61 才知道是从C里搞出来的,先不看这个C的源码了,有机会可以分解一下这个module.js的源码