4kochi
4kochi

Reputation: 118

Mock module which returns a function in node.js

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

Answers (1)

Krasimir
Krasimir

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

Related Questions