josiah
josiah

Reputation: 1414

How would I stub an fs callback's injected params to remove the need to touch the filesystem in a test suite?

I'm using Chai, Mocha, and Sinon for my testing framework.

Right now, I have a test for this working, but I actually have to create a directory and put files in it to get my tests to actually do something (this will be a large test suite, so doing things with all this diskIO is not ideal, to say the least). How can I stub out the injection mechanism so that I don't have to touch the disk in the test?

I was thinking, in the example code below, some way to stub the err and the files parameters injected by the fs.readdir method. That way, I avoid testing fs.readdir in my unit test. I did some Googling and looked at the API Docs but I didn't find what I needed (or didn't recognize it).

Here is some sample code of what I'm talking about:

Function under test

function fsFxnWrapper(dir, callback) {
  var doSomeMutation = function (files) {
    ...
  };

  fs.readdir(dir, function(err, files) {
    callback(err, doSomeMutation(files));
  });
}

Sample Test Case

describe('When the directory has things'', function () {
  before(function () {
    ...
  });

  after(function () {
    ...
  });

  // I'm not sure how to write my stubs so that fs.readdir inside of the
  // fsFxnWrapper doesn't have to go out to the filesystem to retrieve something...
  it('should do the proper mutation on the files list', function () {
    var valueAfterMutation = [ /* the expected answer */];
    fsFxnWrapper('test/dir', function (err, files) {
      expect(files).to.deep.equal(valueAfterMutation);
      expect(err).to.equal(null);
    });
  });
});

Upvotes: 0

Views: 257

Answers (2)

Kirill Slatin
Kirill Slatin

Reputation: 6153

You might consider some mocking libraries if you work under Node.js: node-mocks, mock-fs

Upvotes: 1

gconsidine
gconsidine

Reputation: 155

One way you could go about it would be to structure your module like this:

var Example = function (fs) {
  fs = fs || require('fs');

  this.fsFxnWrapper = function(dir, callback) {
    var doSomeMutation = function (files) {
      ...
    };

    fs.readdir(dir, function(err, files) {
      callback(err, doSomeMutation(files));
    });
  }
};

module.exports = Example;

Then you could mock fs before you pass it into the constructor of the module:

describe('When the directory has things'', function () {
  it('should do the proper mutation on the files list', function () {

    var Example = require('Example');
    var fs = require('fs');

    fs.readir = function () {
      // your alternative implementation that doesn't touch the filesystem
    }

    var example = new Example(fs);
    var valueAfterMutation = [ /* the expected answer */];

    example.fsFxnWrapper('test/dir', function (err, files) {
      expect(files).to.deep.equal(valueAfterMutation);
      expect(err).to.equal(null);
    });
  });
});

I'd be curious to hear from others on this though because I've been using this approach in places, and while it works, I'm not sure if a more ideal solution exists.

Hope that helps.

Upvotes: 1

Related Questions