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

我们有一些我们想要testing的node.js代码。 这些是返回一个函数的模块( module.exports = function(){…} )。 在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 }; 

所以在testing中,我们要模拟/存根函数repo.validate()。 但是到现在为止,我们没有办法做到这一点。 我们testing的所有node.js mocking框架/库可以模拟一个模块,然后你可以覆盖导出。 但在我们的例子中,模块返回一个函数,而在控制器中,repo已经被实例化了。

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

谢谢你的帮助。

我不认为你可以解决这个问题,而不需要改变你的代码。 这是因为repovariables是userRepo.js的私有variables。 不过,我真的很喜欢这样的情况,因为现在你发现模块devise不正确,无法完全testing。 我会这样写。

 // 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; }; 

所以,做这样的事情,你将能够模拟repovariables,并通过自定义validation方法传递自己的变体。 当然问题是你应该改变你使用userRepo.js的地方

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

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

但它是值得的。 因为在你的testing中你可能会写:

 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(); 

所以我的build议是:在开始写东西之前,问问自己:“我要如何去testing它?”。