模块模块,它返回node.js中的一个函数

时间:2013-12-20 07:42:41

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

我们想要测试一些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。

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

感谢您的帮助。

1 个答案:

答案 0 :(得分: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 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();

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