How to unit test a Node.js module that requires other modules and how to mock the global require function?

Solution 1:

You can now!

I published proxyquire which will take care of overriding the global require inside your module while you are testing it.

This means you need no changes to your code in order to inject mocks for required modules.

Proxyquire has a very simple api which allows resolving the module you are trying to test and pass along mocks/stubs for its required modules in one simple step.

@Raynos is right that traditionally you had to resort to not very ideal solutions in order to achieve that or do bottom-up development instead

Which is the main reason why I created proxyquire - to allow top-down test driven development without any hassle.

Have a look at the documentation and the examples in order to gauge if it will fit your needs.

Solution 2:

A better option in this case is to mock methods of the module that gets returned.

For better or worse, most node.js modules are singletons; two pieces of code that require() the same module get the same reference to that module.

You can leverage this and use something like sinon to mock out items that are required. mocha test follows:

// in your testfile
var innerLib  = require('./path/to/innerLib');
var underTest = require('./path/to/underTest');
var sinon     = require('sinon');

describe("underTest", function() {
  it("does something", function() {
    sinon.stub(innerLib, 'toCrazyCrap').callsFake(function() {
      // whatever you would like innerLib.toCrazyCrap to do under test
    });

    underTest();

    sinon.assert.calledOnce(innerLib.toCrazyCrap); // sinon assertion

    innerLib.toCrazyCrap.restore(); // restore original functionality
  });
});

Sinon has good integration with chai for making assertions, and I wrote a module to integrate sinon with mocha to allow for easier spy/stub cleanup (to avoid test pollution.)

Note that underTest cannot be mocked in the same way, as underTest returns only a function.

Another option is to use Jest mocks. Follow up on their page

Solution 3:

I use mock-require. Make sure you define your mocks before you require the module to be tested.

Solution 4:

Mocking require feels like a nasty hack to me. I would personally try to avoid it and refactor the code to make it more testable. There are various approaches to handle dependencies.

1) pass dependencies as arguments

function underTest(innerLib) {
    return innerLib.doComplexStuff();
}

This will make the code universally testable. The downside is that you need to pass dependencies around, which can make the code look more complicated.

2) implement the module as a class, then use class methods/ properties to obtain dependencies

(This is a contrived example, where class usage is not reasonable, but it conveys the idea) (ES6 example)

const innerLib = require('./path/to/innerLib')

class underTestClass {
    getInnerLib () {
        return innerLib
    }

    underTestMethod () {
        return this.getInnerLib().doComplexStuff()
    }
}

Now you can easily stub getInnerLib method to test your code. The code becomes more verbose, but also easier to test.