【问题标题】:Mock module which returns a function in node.js在 node.js 中返回函数的模拟模块
【发布时间】:2014-01-09 00:29:50
【问题描述】:

我们有一些想要测试的 node.js 代码。这些是返回函数的模块 (module.exports = function(){...})。在函数内部,还需要一些其他模块。现在我们要模拟这些模块。请参见下面的示例:

// userRepo.js
module.exports = function(connection) {
    // init the repo
    var repo = DB.connect(connection);    

    // add validation function
    repo.validate = function(data, cb) {
        // do validation stuff
        cb(error, result);
    };

    return repo;
};

// userController.js
module.exports = function(config) {
    var repo = require('userRepo.js')(config.connectionStringToUserDB)
    var pub = {};

    pub.create = function(data, cb) {
        repo.validate(data, function(err, res) {
            // do some stuff
        };
    };

    return pub;
}

// the test
var sut = require('userController.js')(anyConfig);

sut.create({}, function(err, res) {
    // do some assertions here
};

所以在测试中我们想要模拟/存根函数 repo.validate()。但直到现在我们发现没有办法做到这一点。我们测试的所有 node.js 模拟框架/库都可以模拟一个模块,然后您可以覆盖导出。但在我们的例子中,模块返回一个函数,并且在控制器中 repo 已经被实例化了。

我希望我的解释是可以理解的 :-)

感谢您的帮助。

【问题讨论】:

    标签: javascript node.js unit-testing testing mocking


    【解决方案1】:

    我认为如果不更改代码中的某些内容就无法解决问题。那是因为repo 变量是userRepo.js 的私有变量。但是我真的很喜欢这种情况,因为现在你发现模块设计不正确,无法完全测试。我就这样写吧。

    // userRepo.js
    module.exports = function(connection) {
    
        var api = {}, repo;
    
        api.setRepo = function(r) {
          repo = r;
        }
        api.getRepo = function() {
          return repo;
        }
        api.init = function() {
    
          // init the repo
          repo = repo || DB.connect(connection);
    
          // add validation function
          repo.validate = function(data, cb) {
              // do validation stuff
              cb(error, result);
          };
    
        }
    
        return api;
    };
    

    因此,做类似的事情,您将能够模拟repo varialbe 并使用自定义验证方法传递您自己的变体。当然问题是你应该把你使用userRepo.js的地方从

    var userRepo = require("./userRepo.js")(connection)
    

    var userRepo = require("./userRepo.js")(connection).init();
    

    但值得。因为在你的测试中你可能会写:

    var userRepo = require("./userRepo.js")(connection).setRepo(customRepo).init();
    

    甚至

    var userRepo = require("./userRepo.js")(connection);
    var repo = userRepo.getRepo();
    repo.validate = function() {
       // custom stuff here
    }
    userRepo.init();
    

    所以我的建议是:在开始写之前问问自己“我将如何测试它?”。

    【讨论】:

    • 你是对的。最好注入或获取/设置 repo 以便于模拟。我的问题是,当调用控制器时,调用者不知道 repo,只有控制器知道它。但是当注入的仓库为空时,我可以注入它并使用默认值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-30
    • 2011-12-27
    • 2013-07-03
    • 2014-06-20
    • 1970-01-01
    • 2016-05-10
    • 1970-01-01
    相关资源
    最近更新 更多