Last active
February 27, 2020 08:08
-
-
Save StephaneTrebel/0c90fc435b6d93f297f52c72b3fddfb6 to your computer and use it in GitHub Desktop.
Unit testing in nodejs with proxyquire and sinon
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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