Node.js中返回函数的模拟模块

4
我们有一些想要测试的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模拟框架/库都可以模拟一个模块,然后您可以重写exports。但是在我们的情况下,该模块返回一个函数,并且在控制器中,repo已经被实例化了。我希望我的解释是可理解的:-) 感谢任何帮助。
1个回答

2

我认为如果不在你的代码中做出一些更改,你将无法解决这个问题。这是因为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变量并传递带有自定义验证方法的自己的变量。当然问题在于您应该更改使用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,只有控制器知道它。但是我可以注入它并在注入的repo为空时使用默认值。 - 4kochi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接