【问题标题】:Stub out module function存根模块功能
【发布时间】:2014-08-08 02:50:45
【问题描述】:

编辑:更精确一点。

我想测试我们团队创建的 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(...) 期望我传递一个对象和一个方法,并且不允许我存根作为函数的模块。

有什么想法吗?

【问题讨论】:

    标签: javascript node.js sinon


    【解决方案1】:

    在纯诗乃中可能有一种方法可以实现这一点,但我怀疑它会很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 中所述,一般来说,此功能是单元测试设计不佳的标志,应避免使用。

    【讨论】:

    • 好吧,我有点不清楚。我不想只在测试范围内存根模块,我想为我在测试中使用的每个模块存根它。如果我在测试中直接调用 github(...),您的解决方案有效,但所有其他模块仍使用原始实现。
    • Proxyquire 可以做到这一点;尽管他们在文档中建议不要这样做,称这通常是单元测试设计不佳的标志。见这里:github.com/thlorenz/proxyquire#globally-override-require。我会更新我的答案来提及这一点。
    【解决方案2】:

    我发现这对我有用...

    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!'
    

    【讨论】:

      【解决方案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 () {
          ... 
      });
      

      【讨论】:

        【解决方案4】:

        如果你在做

        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!!");
        });
        

        【讨论】:

        • 这不起作用:TypeError: Attempted to wrap undefined property github as function
        • 你在哪里执行 sinon.stub(..)?它也应该在全局范围内。或者你可以试试var stub_github = sinon.stub(global, "github", function (args, callback) { console.log("the github(...) call was stubbed out!!"); });
        • 也不起作用。 sinon.stub(...) 在测试用例中被调用,“github”被定义在同一个范围内。
        猜你喜欢
        • 1970-01-01
        • 2019-04-03
        • 1970-01-01
        • 2014-08-29
        • 1970-01-01
        • 2011-12-26
        • 2014-10-09
        • 2023-04-07
        • 2011-09-17
        相关资源
        最近更新 更多