存根模块功能

时间:2014-06-17 23:25:28

标签: javascript node.js sinon

编辑:更准确一点。

我想为我们团队创建的Github API包装器扩展测试用例。对于测试,我们不希望直接使用API​​包装器扩展,因此我们希望将其功能存根。所有对API包装器的调用都应该用于测试,而不仅仅是创建克隆存根。

我在Node.js中有一个模块“github”:

module.exports = function(args, done) {
    ...
}

我要求这样:

var github = require('../services/github');

现在,我想使用Sinon.js来隐藏github(...)

var stub_github = sinon.stub(???, "github", function (args, callback) { 
    console.log("the github(...) call was stubbed out!!");
});

但是sinon.stub(...)希望我传递一个对象和一个方法,并且不允许我删除一个函数模块。

有什么想法吗?

4 个答案:

答案 0 :(得分:8)

在纯粹的Sinon中可能有一种方法可以实现这一点,但我怀疑它会非常hacky。但是,proxyquire是一个用于解决此类问题的节点库。

假设您要测试一些使用github模块的模块foo;你会写一些类似的东西:

var proxyquire = require("proxyquire");
var foo = proxyquire(".foo", {"./github", myFakeGithubStub});

myFakeGithubStub可以是任何东西;一个完整的存根,或实际的实现,有一些调整等。

如果在上面的示例中,myFakeGithubStub将属性“@global”设置为true,(即通过执行myFakeGithubStub["@global"] = true),那么github模块将被替换为存根,不仅仅是foo模块本身,但在foo模块所需的任何模块中。但是,正如proxyquire documentation on the global option中所述,一般来说,此功能是设计不良的单元测试的标志,应该避免使用。

答案 1 :(得分:5)

我发现这对我有用......

const sinon          = require( 'sinon' );
const moduleFunction = require( 'moduleFunction' );

//    Required modules get added require.cache. 
//    The property name of the object containing the module in require.cache is 
//    the fully qualified path of the module e.g. '/Users/Bill/project/node_modules/moduleFunction/index.js'
//    You can get the fully qualified path of a module from require.resolve
//    The reference to the module itself is the exports property

const stubbedModule = sinon.stub( require.cache[ require.resolve( 'moduleFunction' ) ], 'exports', () => {

    //    this function will replace the module

    return 'I\'m stubbed!';
});

// sidenote - stubbedModule.default references the original module...

你必须确保在其他地方需要之前将模块(如上所述)存根...

// elsewhere...

const moduleFunction = require( 'moduleFunction' ); 

moduleFunction();    // returns 'I'm stubbed!'

答案 2 :(得分:3)

最简单的解决方案是重构您的模块:

而不是:

module.exports = function(args, done) {
    ...
}

这样做:

module.exports = function(){
    return module.exports.github.apply(this, arguments);
};
module.exports.github = github;

function github(args, done) {
    ...
}

现在你可以要求:

const github = require('../services/github.js');
//or
const github = require('../services/github.js').github;

要存根:

const github = require('../services/github.js');
let githubStub = sinon.stub(github, 'github', function () {
    ... 
});

答案 3 :(得分:-2)

如果你正在做

var github = require('../services/github');

在全局范围内,那么你可以使用'global'作为对象,'github'作为要删除的方法。

var stub_github = sinon.stub(global, "github", function (args, callback) { 
    console.log("the github(...) call was stubbed out!!");
});