Reputation: 118
We have some node.js code we want to test. These are modules which return a function (module.exports = function(){...}). Inside the function some other modules are required. Now we want to mock these modules. See example below:
// 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
};
So in the test we want to mock/stub the function repo.validate(). But until now we found no way doing this. All the node.js mocking frameworks/libs we tested can mock a module and then you can override the exports. But in our case the module returns a function and in the controller the repo is already instantiated.
I hope my explanations are understandable :-)
Thanks for any help.
Upvotes: 4
Views: 1039
Reputation: 13549
I don't think that you could solve the problem without to change something in your code. That's because repo
variable is a private one for userRepo.js
. However I really like such situations, because now you find out that the module is not designed properly and can not be fully tested. I'll write it like that.
// 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;
};
So, doing the things like that you will be able to mockup the repo
varialbe and pass your own variant with a custom validate method. Of course the problem is that you should change the places where you use userRepo.js
from
var userRepo = require("./userRepo.js")(connection)
to
var userRepo = require("./userRepo.js")(connection).init();
but it worth it. Because in your tests you may write:
var userRepo = require("./userRepo.js")(connection).setRepo(customRepo).init();
or even
var userRepo = require("./userRepo.js")(connection);
var repo = userRepo.getRepo();
repo.validate = function() {
// custom stuff here
}
userRepo.init();
So my advice is: before to start writing something ask yourself "How I'm going to test it?".
Upvotes: 2