I searched the site because I assumed this question must have been asked already but came up empty.
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 and all other built-ins as an argument to all of my functions to avoid the real fs from being used. This seems a little bit silly and creates a verbose function signature crowded with built ins as arguments.
var fs = require('fs');
function findFile(path, callback) {
_findFile(fs, path, callback);
}
function _findFile(fs, path, callback) {
fs.readdir(path, function(err, files) {
//Do something.
});
}
And then during testing:
var stubFs = {
readdir: function(path, callback) {
callback(null, []);
}
};
_findFile.(stubFs, testThing, testCallback);
There's a better way than this right?
I like using rewire for stubbing out require(...) statements
module-a.js
var fs = require('fs')
function findFile(path, callback) {
fs.readdir(path, function(err, files) {
//Do something.
})
}
module-a-test.js
var rewire = require('rewire')
var moduleA = rewire('./moduleA')
// stub out fs
var fsStub = {
readdir: function(path, callback) {
console.log('fs.readdir stub called')
callback(null, [])
}
moduleA.__set__('fs', fsStub)
// call moduleA which now has a fs stubbed out
moduleA()
An alternative (although I think Noah's suggestion of rewire is better):
Write a wrapper around require, named requireStubbable or so. Put this in a module which you configure once, in test setup code. Because node caches result of require, whenever you require the requireStubbable module again, you'd get the same configured function. You could configure it so that any number of modules would be stubbed, all others would be passed on unchanged.
Any module which you'd want to support passing in stubs need to use the requireStubbable function instead of regular require though. The rewire module does not have that drawback, and instead gives control to the calling code.
I've never realized, but since the object (or more precisely: object reference) returned by require("fs") is cached, you could simply do:
fs = require("fs)
fs.readFile = function (filename, cb) { cb(null, new Buffer("fake contents")}
// etc
When you include this code anywhere, fs.readFile will be pointing to the above function everywhere. This works for stubbing out any module that is a mere collection of functions (like most built-in modules). The cases for which it doesn't work if the module returns a sole function. For this, something like "rewire" would be necessary.
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.
Check out mock-fs and fake-fs, which do a lot of this already.
var fs = require('./myStubFs');
Would seem to be a big improvement. Whatever solution you find will probably involve writing your own stub functions. The ideal solution would be lower level so you don't have to touch all the files you want doing this, e.g. perhaps you want 3rd party libraries stubbed out as well.