IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    nodejs非导出方法测试

    草依山发表于 2014-09-09 03:34:41
    love 0

    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的源码


    文章来源: nodejs非导出方法测试
    文章的标签: nodejs


沪ICP备19023445号-2号
友情链接