In node.js testing, there are 2 helper modules that I use often: sinon and rewire. Sinon allows you to monkey-patch functions, while rewire allows you to… monkey-patch functions. Both modules have other uses as well, but in this post I’m focusing on monkey-patching.
So, in which situations should you use sinon and when should you use rewire for monkey-patching?
In short: if you are testing module A, and inside module A there is a call to a function of module B, you should use sinon. If you want to monkey-patch a call to a function inside module A itself, you should use rewire (and optionally, sinon as well).
Here is an example.
// a.js var b = require('b'); function testMe(num) { return { x: a1(num), y: b.b1(num), } } function a1(num) { return 2 * num; } module.exports = { test: test };
// b.js function b1(num) { return 5 * num; } module.exports = { b1: b1 };
In your test file, when you are testing testMe , you can mock b.b1 by doing this:
var b = require('b'); var b1mock = sinon.mock(b, 'b1');
This works, because in node.js, each require() ‘ed module is a singleton. So the b in your test file is the same as the b in a.js . Therefore, sinon can overwrite the b.b1 function in the test file, which results in the call to b.b1 inside testMe ending up in sinon’s mock.
Unfortunately, this doesn’t work for the a1 call. This function is not exported by a.js , and even if it was, overwriting it with sinon would not have any effect. The reason for this, is that a1 is called “directly” from testMe.
One way to work around this, is to modify the source code in the following way.
// a.js - modified (ugly! don't do this!) var b = require('b'); function test(num) { return { x: module.exports.a1(num), y: b.b1(num), } } function a1(num) { return 2 * num; } module.exports = { a1: a1, test: test };
In your test file, you can now require(‘./a’) and use sinon to mock a.a1() . Ugh. This is not elegant at all.
Fortunately, rewire allows us to overwrite even private functions. All you need to do in your test file is the following:
var a = rewire('a'); var a1mock = sinon.mock(); // Overwrite the private a1 function with the mock. var restore = a.__set__('a1', a1mock); // Do your test. // Restore the original a1 function. restore();
This is a bit more work, but at least you don’t need to change the source code.
One Response to sinon vs rewire: when do I use which?