node js unit testing: mocking require dependency
Asked Answered
O

1

8

I am having issues writing unit test for the following setup as a jira.js file (in a node.js module):

var rest = require('restler'); // https://www.npmjs.com/package/restler

module.exports = function (conf) {
    var exported = {};

    exported.getIssue = function (issueId, done) {
        ...

        rest.get(uri).on('complete', function(data, response) {
        ...
    };

    return exported;
};

Now, i want to write unit test for my getIssue function. 'restler' is a REST client through which i make REST calls to the JIRA API to get a JIRA issue via my code.

So to be able to test createIssue(..), I want to be able to mock the 'rest' var in my Jasmine unit tests.

How can i mock this method? Please give me some pointers so that i can go ahead. I have tried using rewire but i have failed.

This is what i have so far which does not work (ie. getIssue method turns out to be undefined):

var rewire       = require("rewire");
var EventEmitter = require('events').EventEmitter;
var emitter      = new EventEmitter();
var cfg          = require("../../../config.js").Configuration;
var jiraModule   = rewire("../lib/jira")(cfg);
var sinon        = require("sinon");
var should       = require("should");

// https://github.com/danwrong/restler
var restMock = {
    init : function () {
        console.log('mock initiated'+JSON.stringify(this));

    },
    postJson : function (url, data, options) {
        console.log('[restler] POST url='+url+', data= '+JSON.stringify(data)+
        'options='+JSON.stringify(options));
        emitter.once('name_of_event',function(data){
            console.log('EVent received!'+data);
        });
        emitter.emit('name_of_event', "test");
        emitter.emit('name_of_event');
        emitter.emit('name_of_event');
    }, 
    get : function (url, options) {
        console.log('[restler] GET url='+url+'options='+JSON.stringify(options));
    },
    del : function (url, options) {
        console.log('[restler] DELETE url='+url+'options='+JSON.stringify(options));
    },
    putJson : function (url, data, options) {
        console.log('[restler] PUT url='+url+', data= '+JSON.stringify(data)+
        'options='+JSON.stringify(options));
    }
};

var cfgMock = {
    "test" : "testing"
};

jiraModule.__set__("rest", restMock);
jiraModule.__set__("cfg", cfgMock);

console.log('mod='+JSON.stringify(jiraModule.__get__("rest")));

describe("A suite", function() {
it("contains spec with an expectation", function() {
    restMock.init();
    restMock.postJson(null, null, null);

console.log(cfg.jira);

    // the following method turns out to be undefined but when i console.log out the jiraModule, i see the entire code outputted from that file
    jiraModule.getIssue("SRMAPP-130", function (err, result) {
        console.log('data= '+JSON.stringify(result));
     });

    expect(true).toBe(true);
});
});

If someone can guide me on how to mock the 'rest' require dependency & unit test this method that will be very helpful.

Also, how should i mock the 'conf' being passed to module.exports?

thanks

Obviate answered 18/11, 2015 at 5:22 Comment(0)
C
7

You could use proxyquire or mockery to stub/mock the dependencies.

In the below example I have used proxyquire. Hope it helps.


/* ./src/index.js */
var rest = require('restler');

module.exports = function (conf) {
  var exported = {};

  exported.getIssue = function (issueId, done) {
    var uri = '';
    var reqObj = '';
    var service = {
      auth : ''
    };

    rest.postJson(uri, reqObj, service.auth).on('complete', function(data, response) {
      done(data, response);
    });
  };

  return exported;
};

/* ./test/index.js */
var proxyquire  =  require('proxyquire');
var assert      =  require('chai').assert;
var restlerStub = {
  postJson: function() {
    return {
      on: function(event, callback) {
        callback('data', 'response');
      }
    }
  }
}

var index = proxyquire('../src/index', {'restler': restlerStub})();

describe('index', function() {
  it('should return the desired issue', function(done) {
    var issue = index.getIssue('issueId', function(data, response) {
      assert.equal(data, 'data');
      assert.equal(response, 'response');
      done();
    })
  });
});

/* ./package.json */
{
  "scripts": {
    "test": "mocha"
  },
  "dependencies": {
    "restler": "^3.4.0"
  },
  "devDependencies": {
    "chai": "^3.4.1",
    "mocha": "^2.3.4",
    "proxyquire": "^1.7.3"
  }
}
Calcine answered 18/11, 2015 at 6:31 Comment(9)
Jasmine-node is tagged, why are you using mocha?Occiput
Opps, I did not notice that, however mocking the dependency has nothing to do with the test framework.Calcine
hello, thanks for the guidance!! how do i pass in the conf if i am using proxyquire? I need to mock conf as well....which is taken as an argument by module.exports..Obviate
var index = proxyquire('../src/index', {'restler': restlerStub})(conf);Calcine
thanks! this explanation looks promising. One more thing before i try out and see if this works. I am not sure how to fire the 'complete' event for testing (if you look at the rest call, it throws an event). Will the stub for 'restlerSTub' given above work in this case? or do i have to use eventemitter and emit an event from my restlerStub function?Obviate
rest.postJson().on() could be comprehended as rest.postJson() returns and object which has a on method; {on: function(){}}, this on method is subsequently called. If you see the stub its doing the same. You could use EventEmitter too.Calcine
thanks sarbbottam. This is really a great suggestion! I will test this out and let you know if it worked for me. really appreciate the help!Obviate
excellent! this worked like a charm! thanks a ton for the advise sarbbottam. you rock :)Obviate
You have to use jest mocks if you are using jest frameworkGualtiero

© 2022 - 2024 — McMap. All rights reserved.