Skip to content

Instantly share code, notes, and snippets.

@StephaneTrebel
Last active February 27, 2020 08:08
Show Gist options
  • Save StephaneTrebel/0c90fc435b6d93f297f52c72b3fddfb6 to your computer and use it in GitHub Desktop.
Save StephaneTrebel/0c90fc435b6d93f297f52c72b3fddfb6 to your computer and use it in GitHub Desktop.
Unit testing in nodejs with proxyquire and sinon
// Awesomeness first
const _ = require('lodash');
const proxyquire = require('proxyquire');
const sinon = require('sinon');
// Mocha + Chai are used here but feel free to use your test framework of choice !
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
// Start with defining your module name
const testedModuleName = 'path/to/my/tested/module';
// This function is used as a default stub to force you to override it while adding tests
const stubMe = fnName => () => {
throw new Error('Please stub this function call: ' + fnName);
};
/**
* First you prepare your external dependencies to be mocked
* If any external dependency is added to the tested module, you have to add its name here as well
*/
const dep1 = 'path/to/dep1';
const dep2 = 'path/to/dep2';
/**
* Then you prepare a higher order function that will help you easily override the default stub
* If any external dependency is added to the tested module, you have to add its called functions here as well
* As you can see, all default stubs are throwing functions, to ensure you will properly stub in the context of each test,
* and that each test will be independent from the others
*/
const createStubs = customStubs => _.defaults({}, customStubs, {
[dep1]: { fnA: stubMe('fnA') },
[dep2]: {
fnB: stubMe('fnB'),
fnC: stubMe('fnC')
}
});
// Then you can use it in your tests :3
describe('myAwesomeFunction()', () => {
const m = proxyquire(testedModuleName, createStubs({
[dep1]: { fnA: () => 'foobar' },
// Here dep2.fnB is not stubbed because it's not used by myAwesomeFunction
[dep2]: { fnC: () => Promise.resolve('barfob') }
}));
before(() => {
// Stub here all your module functions that the tested function uses (internal dependencies)
sinon.stub(m, 'aLocalFunctionMyAwesomeFunctionUses', () => true);
});
after(() => {
// Restore to ensure you don't silently impact other tests (that should stub this function too !)
m.aLocalFunctionMyAwesomeFunctionUses.restore();
});
it('should do stuff', () => expect(
m.myAwesomeFunction('foo')
)
.to.eventually.be.eql('bar')
);
});
// That's all, folks ! :3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment