Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I mock dependencies for unit testing in RequireJS?

People also ask

What can be mocked for unit testing?

What is mocking? Mocking is a process used in unit testing when the unit being tested has external dependencies. The purpose of mocking is to isolate and focus on the code being tested and not on the behavior or state of external dependencies.

What is dependency mocking?

Mock the dependencies Unit testing is born to test the behavior of a single component — SUT — without caring of its dependencies. The purpose of mocking the dependencies is to keep the SUT isolated from external objects.

Should I mock dependencies?

Don't mock all mutable dependenciesYou shouldn't mock all mutable dependencies. To see why, we need to look at two types of communications in a typical application: intra-system and inter-system. Inter-system communications are when your application talks to other applications.

What are dependencies in unit testing?

So, what is a unit testing dependency? It's a dependency that you must set up in the test before you can exercise the system under test. Dependencies can be explicit, like in the example above, but they also can be implicit.


So after reading this post I came up with a solution that use the requirejs config function to create a new context for your test where you can simply mock your dependencies:

var cnt = 0;
function createContext(stubs) {
  cnt++;
  var map = {};

  var i18n = stubs.i18n;
  stubs.i18n = {
    load: sinon.spy(function(name, req, onLoad) {
      onLoad(i18n);
    })
  };

  _.each(stubs, function(value, key) {
    var stubName = 'stub' + key + cnt;

    map[key] = stubName;

    define(stubName, function() {
      return value;
    });
  });

  return require.config({
    context: "context_" + cnt,
    map: {
      "*": map
    },
    baseUrl: 'js/cfe/app/'
  });
}

So it creates a new context where the definitions for Hurp and Durp will be set by the objects you passed into the function. The Math.random for the name is maybe a bit dirty but it works. Cause if you'll have a bunch of test you need to create new context for every suite to prevent reusing your mocks, or to load mocks when you want the real requirejs module.

In your case it would look like this:

(function () {

  var stubs =  {
    hurp: 'hurp',
    durp: 'durp'
  };
  var context = createContext(stubs);

  context(['yourModuleName'], function (yourModule) {

    //your normal jasmine test starts here

    describe("yourModuleName", function () {
      it('should log', function(){
         spyOn(console, 'log');
         yourModule.foo();

         expect(console.log).toHasBeenCalledWith('hurp');
      })
    });
  });
})();

So I'm using this approach in production for a while and its really robust.


you might want to check out the new Squire.js lib

from the docs:

Squire.js is a dependency injector for Require.js users to make mocking dependencies easy!


I have found three different solutions to this problem, none of them pleasant.

Defining Dependencies Inline

define('hurp', [], function () {
  return {
    beans: 'Beans'
  };
});

define('durp', [], function () {
  return {
    beans: 'durp beans'
  };
});

require('hurpdhurp', function () {
  // test hurpdurp in here
});

Fugly. You have to clutter up your tests with lots of AMD boilerplate.

Loading Mock Dependencies From Different Paths

This involves using a separate config.js file to define paths for each of the dependencies that point to mocks instead of the original dependencies. This is also ugly, requiring the creation of tons of test files and configurations files.

Fake It In Node

This is my current solution, but is still a terrible one.

You create your own define function to provide your own mocks to the module and put your tests in the callback. Then you eval the module to run your tests, like so:

var fs = require('fs')
  , hurp = {
      beans: 'BEANS'
    }
  , durp = {
      beans: 'durp beans'
    }
  , hurpDurp = fs.readFileSync('path/to/hurpDurp', 'utf8');
  ;



function define(deps, cb) {
  var TestableHurpDurp = cb(hurp, durp);
  // now run tests below on TestableHurpDurp, which is using your
  // passed-in mocks as dependencies.
}

// evaluate the AMD module, running your mocked define function and your tests.
eval(hurpDurp);

This is my preferred solution. It looks a little magic, but it has a few benefits.

  1. Run your tests in node, so no messing with browser automation.
  2. Less need for messy AMD boilerplate in your tests.
  3. You get to use eval in anger, and imagine Crockford exploding with rage.

It still has some drawbacks, obviously.

  1. Since you are testing in node, you can't do anything with browser events or DOM manipulation. Only good for testing logic.
  2. Still a little clunky to set up. You need to mock out define in every test, since that is where your tests actually run.

I am working on a test runner to give a nicer syntax for this kind of stuff, but I still have no good solution for problem 1.

Conclusion

Mocking deps in requirejs sucks hard. I found a way that sortof works, but am still not very happy with it. Please let me know if you have any better ideas.


There's a config.map option http://requirejs.org/docs/api.html#config-map.

On how-to use it:

  1. Define normal module;
  2. Define stub module;
  3. Configure RequireJS expicitely;

    requirejs.config({
      map: {
        'source/js': {
          'foo': 'normalModule'
        },
        'source/test': {
          'foo': 'stubModule'
        }
      }
    });
    

In this case for normal and test code you could use the foo module which will be real module reference and stub accordingly.