如何对需要其他模块的node.js模块进行单元测试

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (72)
var innerLib = require('./path/to/innerLib');

function underTest() {
    return innerLib.doComplexStuff();
}

module.exports = underTest;

我正试图为这段代码编写一个单元测试。如何模拟innerLib而不使require完全发挥作用?

编辑:所以这是我试图模拟全局需求,发现它甚至不能做到这一点:

var path = require('path'),
    vm = require('vm'),
    fs = require('fs'),
    indexPath = path.join(__dirname, './underTest');

var globalRequire = require;
require = function(name) {
    console.log('require: ' + name);
    switch(name) {
        case 'connect':
        case indexPath:
            return globalRequire(name);
            break;
    }
};

问题是require函数实际上还没有模拟出underTest.js文件中的函数。它仍然指向全球require功能。所以看来我只能模仿require函数在我正在进行模拟的文件中。如果我使用全局require若要包含任何内容,即使在重写了本地副本之后,所需的文件仍将具有全局require推荐信。

提问于
用户回答回答于

这意味着你需要代码没有更改以便为所需模块注入模拟程序。

Proxyquire有一个非常简单的API,它允许在一个简单的步骤中解析您要测试的模块,并传递其所需模块的模拟/存根。

@Raynos是对的,传统上你不得不求助于不太理想的解决方案来实现这一点,或者做自下而上的开发。

这就是为什么我创建proxyquire的主要原因--允许自顶向下的测试驱动开发,而不需要任何麻烦。

用户回答回答于

在这种情况下,一个更好的选择是模拟返回的模块的方法。

无论好坏,大多数node.js模块都是单例;需要()的两段代码相同模块获得相同的引用。

// in your testfile
var innerLib  = require('./path/to/innerLib');
var underTest = require('./path/to/underTest');
var sinon     = require('sinon');

describe("underTest", function() {
  it("does something", function() {
    sinon.stub(innerLib, 'toCrazyCrap', function() {
      // whatever you would like innerLib.toCrazyCrap to do under test
    });

    underTest();

    sinon.assert.calledOnce(innerLib.toCrazyCrap); // sinon assertion

    innerLib.toCrazyCrap.restore(); // restore original functionality
  });
});

请注意,不能以相同的方式对欠测试进行模拟,因为欠测试只返回一个函数。

扫码关注云+社区

领取腾讯云代金券