Skip to content

Instantly share code, notes, and snippets.

@froots froots/Car.js
Last active Jun 6, 2018

Embed
What would you like to do?
Stubbing module dependencies in ES2015 unit tests using Sinon.js or TestDouble.js.

I was all set up for the pain of stubbing Node.js dependencies, but you can just use the import * as blah from 'blah' syntax to obtain an object with properties that can be stubbed using either TestDouble or Sinon.

The object is shared between modules at runtime, so modifications will propagate everywhere. Be sure the use Sinon's restore() or TestDouble's reset() methods to return the module to it's normal state so that it doesn't bleed into other tests.

If you need to stub a default module function, then use this import

import * as kphToMphModule from '../src/kphToMph';

and stub with testdouble like this:

const kphToMph = td.replace(kphToMphModule, 'default');

or with Sinon:

const kphToMph = sinon.stub(kphToMphModule, 'default');

// in /src directory
import {kphToMph} from './convert';
class Car {
constructor(speed) {
this.speed = speed;
}
getSpeedInMph() {
return kphToMph(this.speed);
}
}
export default Car;
// In /src directory
export function kphToMph(speed) {
// Real function here
return 0;
}
{
"devDependencies": {
"babel-cli": "^6.14.0",
"babel-preset-es2015": "^6.14.0",
"babel-register": "^6.14.0",
"mocha": "^3.0.2",
"sinon": "^1.17.5",
"testdouble": "^1.6.1"
},
"scripts": {
"test": "mocha --compilers js:babel-register"
}
}
// Goes in /test directory
import assert from 'assert';
import sinon from 'sinon';
// Subject
import Car from '../src/Car';
// Dependency of subject - import whole module as an object
import * as convert from '../src/convert';
describe('Car', () => {
afterEach(() => {
// Need to reset any replaced methods
convert.kphToMph.restore();
});
it('returns speed converted to MPH', () => {
// Replace the internal dependency of Car
const getSpeedInMph = sinon.stub(convert, 'kphToMph');
// When the dependent method is called, return a fixed value
getSpeedInMph.withArgs(50).returns(31);
const car = new Car(50);
// Call the function that uses the dependency
// This will now call the replaced function
const actual = car.getSpeedInMph();
// Our expected value
const expected = 31;
assert.equal(actual, expected);
});
});
// Goes in /test directory
import assert from 'assert';
import td from 'testdouble';
// Subject
import Car from '../src/Car';
// Dependency of subject - import whole module as an object
import * as convert from '../src/convert';
describe('Car', () => {
afterEach(() => {
// Need to reset any replaced methods
td.reset();
});
it('returns speed converted to MPH', () => {
// Replace the internal dependency of Car
const kphToMph = td.replace(convert, 'kphToMph');
// When the dependent method is called, return a fixed value
td.when(kphToMph(50)).thenReturn(31);
const car = new Car(50);
// Call the function that uses the dependency
// This will now call the replaced function
const actual = car.getSpeedInMph();
// Our expected value
const expected = 31;
assert.equal(actual, expected);
});
});
@Strajk

This comment has been minimized.

Copy link

Strajk commented Sep 8, 2016

Does not work with add-module-exports preset, found out a hard way :(

https://ide.c9.io/strajk/node-stubbing-module-deps

@searls

This comment has been minimized.

Copy link

searls commented Sep 18, 2016

looks pretty cool. unsure i'll be able to do any better with testdouble.js since import is (theoretically) totally static, even if there might be a sneaky way to accomplish this as long as folks are transpiling it in

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.