Mocking a nested module in Node.js?
Asked Answered
G

2

5

I have these files:

File1.js

var mod1 = require('mod1');
mod1.someFunction()
...

File2.js

var File1 = require('./File1');

Now while writing unit tests for File2, is it possible to have mod1 mocked, so that I don't make calls to mod1.someFunction()?

Govern answered 1/2, 2016 at 19:40 Comment(4)
Yes it is possible. You should read something about dependency injection. And have a look at sinon.js.Midway
Take a look at this tutorial on mocking: youtube.com/watch?v=fgqh-OZjpYY It shows a technique you can use just for this. And yeah, definitely check out sinon.Teacart
how will sinon address this?Epanodos
Sinon helps with creating stubs for the functions being created, so that it's easy to verify whether they were called correctly, return the correct values, etc.Govern
P
5

I'm usually using mockery module like following:

lib/file1.js

var mod1 = require('./mod1');
mod1.someFunction();

lib/file2.js

var file1 = require('./file1');

lib/mod1.js

module.exports.someFunction = function() {
  console.log('hello from mod1');
};

test/file1.js

/* globals describe, before, beforeEach, after, afterEach, it */

'use strict';

//var chai = require('chai');
//var assert = chai.assert;
//var expect = chai.expect;
//var should = chai.should();

var mockery = require('mockery');

describe('config-dir-all', function () {

  before('before', function () {
    // Mocking the mod1 module
    var mod1Mock = {
      someFunction: function() {
        console.log('hello from mocked function');
      }
    };

    // replace the module with mock for any `require`
    mockery.registerMock('mod1', mod1Mock);

    // set additional parameters
    mockery.enable({
      useCleanCache:      true,
      //warnOnReplace:      false,
      warnOnUnregistered: false
    });
  });

  beforeEach('before', function () {

  });

  afterEach('after', function () {

  });

  after('after', function () {
    // Cleanup mockery
    after(function() {
      mockery.disable();
      mockery.deregisterMock('mod1');
    });
  });

  it('should throw if directory does not exists', function () {

    // Now File2 will use mock object instead of real mod1 module
    var file2 = require('../lib/file2');

  });

});

As it was suggested before, sinon module is very convenient to build the mocks.

Pierpont answered 1/2, 2016 at 19:57 Comment(2)
Thanks, that worked! I was actually trying Mockery before, but had the name of the mock in quotes, and didn't realize.Govern
Hmm.. didn't work for me. Not sure why. Maybe because the nested require is using relative path for require?Immix
E
2

Absolutely. There are 2 very popular node.js libraries exclusively for the purpose of mocking requires.

https://github.com/jhnns/rewire

https://github.com/mfncooper/mockery

Both of them have different API, and rewire has some strange caveats

Epanodos answered 1/2, 2016 at 19:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.