sinplus

0.2.0 • Public • Published

sinplus

A simple solution for mocking Node.js modules.

Beware, user! This software is still in pre-alpha development stage. It is used in other projects, yet is it very possible, that some (serious) bugs are still there. If you use this module, it is strongly advised to use the latest version.

The problem

When you need to test a module, it is very important to test the right thing. Loading modules with require cause the real modules to be loaded, which might not be what you want. When you want to perform a unit test, you need the tested module, and only this module to be loaded, and not everything else.

This problem can be solved either with dependency injection, or with providing a substitute for the require function. The module sinplus is supposed to use the latter approach.

Usage

For tester

In your tests, you should load the sinplus module:

var sinplus = require('sinplus');

Using the module, you can have full control over modules loading (which is crucial for testing) - provided, that your modules are properly prepared (see the section for uses).

There are three actions, you'll be interested in:

  • telling sinplus, which modules should be stubbed,
  • telling sinplus, which modules should not be stubbed,
  • resetting the sinplus module.

You'll be also interested in preparing stubs; it will be explained in the section on stubbing modules.

Resetting the sinplus module

The require function, which comes from the Node.js platform, caches all the loaded modules. Sometimes it might be a good solution, and sometimes it might be a bad idea. For the testing purposes, though, it means, that you cannot simply reload the sinplus module before firing a new test case. So, you need a way to reset the module, and that's why the sinplus.reset function is for. The function should be called before the module is configured (every time you need to tell it, which modules should be stubbed, and which shouldn't).

Here is a simple example:

beforeEach( function() {
  sinplus.reset();
});

No stubs, please!

Sometimes, you might not want some modules to be stubbed (e.g. while performing integration tests). For such purpose, you can configure the sinplus module to not stub them, using the sinplus.configure method:

sinplus.configure('no-stubs', 'lodash');

OK, it seems, that preventing modules stubbing is quite simple. But what about the modules loaded with more complicated paths?

sinplus.configure('no-stubs', 'my-module');

Yes, it will also work. And it doesn't matter, whether your module's path is "../my-module", or perhaps "/a/very/complicated/path/my-module". The only thing that matters is that the end of you'r module's path should match the name you told the sinplus module to not stub.

By the way, you can set the modules to not be stubbed in many calls:

sinplus.configure('no-stubs', 'my-module-1');
sinplus.configure('no-stubs', 'my-module-2');
sinplus.configure('no-stubs', 'my-module-3');

You can also do it in one call:

sinplus.configure('no-stubs', ['my-module-1', 'my-module-2', 'my-module-3']);

I need a stub!

Now, when you know hot to not stub a module while loading, and how the module's paths are handled, you can learn two more things: how to tell the sinplus module to stub the loaded modules, and how to prepare your stubs.

Let's assume, that you'd like to prepare a stub for the lodash module. The lodash module provides many functions, and usually you don't use them all, just some of them. So, let's assume, that you'd like to prepare a stub for the _.max and _.min methods. You can do it using the sinplus.configure method:

sinplus.configure('require', {
  lodash: {
    min: 4,
    max: 10
  }
});

A few thing to be noted here.

First of all, the require key should be used only once, since any further usage will erase the previously set one. So, the stubs have to be configured just once.

The require key is a POJO. Its keys are modules' names, and the values are used for preparing stubs. In the example above, there will be only two stubs provided: one for the _.min, and one for the _.max function. All other functions from the lodash module won't be stubbed at all.

The third thing to note is that the stubs are often supposed to return some value. For such a case, the value might be provided as the value for the key-named function to be stubbed. So, in the example above, the _.min function is going to return 4 when called.

Now you know, how to get a simple stub. And what you should so, when you need something more complicated? When your stub should throw an exception, are return different values for different parameters?

Well, the stubs used in the sinplus module are simply Sinon.JS stubs. It means, they can do everything the Sinon.JS module allows them to do. If your stub should behave in some more sophisticated way, than just return the same value every time it is called, you should configure it with a function:

sinplus.configure('require', {
  lodash: {
    min: 4,
    max: function(stub) {
      stub.onFirstCall().returns(10)
          .onSecondCall().returns(20);
      stub.returns(50);
    }
  }
});

Always set up the whole environment!

While testing (unit testing, integration testing), it is very important to set up the testing environment properly. Failing this task means the tests won't be performed correctly. Thus, you should always set all your used modules either as required (stubbed), or no-stubs.

If you forget about a module, it won't be loaded at all! (The good news is you'll see an ugly message then, so you'll probably find out, that you'd missed it.)

For user

Import the sinplus module at the beginning of each module:

var sinplus = require('sinplus');

Then, check your environment and substitute the require function, if needed:

var the_require = require;
if ( sinplus.configure('env') === 'test' )
  require = function( path ) {
    return sinplus.require( the_require, path );
  }

And that's all.

A note on the configuration: in the example above, the "env" key is used for checking the environment (either "test" or "production"). The way to check the environment is up to you, and you don't have to use sinplus.configure method at all. What is important, is the usage of the sinplus.require method to load the modules while testing.

License

MIT

Copyright (c) 2014 Tomasz Primke

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Package Sidebar

Install

npm i sinplus

Weekly Downloads

1

Version

0.2.0

License

MIT

Last publish

Collaborators

  • tprimke