I want to stub node.js built-ins like fs
so that I don\'t actually make any system level file calls. The only thing I can think to do is to pass in fs
Stubs are functions/programs that simulate the behaviors of components/modules. Stubs provide canned answers to function calls made during test cases.
An example can be writing a file, without actually doing so.
var fs = require('fs')
var writeFileStub = sinon.stub(fs, 'writeFile', function (path, data, cb) {
return cb(null)
})
expect(writeFileStub).to.be.called
writeFileStub.restore()
Check out mock-fs and fake-fs, which do a lot of this already.
Here's a version that works with the fs.promises api:
const fsMock = sinon.mock(fs.promises);
fsMock.expects('readFile').withArgs('test.json').returns(Promise.resolve(Buffer.from('{}')));
const val = await fs.promises.readFile('test.json');
expect(val.toString()).toEqual('{}');
fsMock.verify();
Here's how i think of this:
The way you do it is the obvious first step but it sucks having to pass those things in everywhere— Callers of your functions shouldn't care that you want to test with mocks. You don't want to just overwrite or monkey-patch the global modules in the global namespace for your test. And the normal dependency injection model is pretty verbose in Javascript since there's no class-local scope.
So around the whole module, I've done like (function(fs, net, http) { … })(fs, net, http);
Then inside the module, if there's a class constructor, make the mocks optional extra parameters to the constructor (or possible properties of a single mocks
object parameter or something) and your test passes in the mocks. Your constructor overwrites the real node modules within only the module's local scope.
Alternately if the module just has static functions; have one such function which initializes the mocks, you can validate that that function is not called in your prod code.
For me, mocking/stubbing a file is not needed, I usually create a temporary file in temporary folder.