Stub/spy on singleton with Sinon - javascript

I have a need to write some unit tests where I check on calls to singleton functions. Basically, if I have this:
const somePackage = require('some-package');
And am calling it with:
somePackage();
I want to be able to spy/stub on this singleton call to prove that it was called. I know how to do this with methods using sinon.stub(somePackage, 'someMethod') but not for just a singleton.
Right now I actually have to write integration tests by executing the code when in reality I want to write unit tests and show that these external methods were called. I'm trusting that the developer of those packages did their own testing for the functionality.

You can spy on any function with sinon:
const spy = sinon.spy(myFunc);
To stub a single function you can use proxyquire as described in this issue:
const proxyquire = require('proxyquire')
const sinon = require('sinon')
const sum = sinon.stub()
const ModuleWithDependency = proxyquire('module', {
'sum': sum
})

Related

Spying on a function used as a constructutor

In one of my unit tests I need to spy on a function which is used as a constructor by another function with Sinon library. As per their documentation
...sinon.spy(object, "method") creates a spy that wraps the existing function object.method. The spy will behave exactly like the original method (including when used as a constructor)...
But so far I have failed to make it work even when trying to spy on a constructor called within the test function let alone called by another function.
Unit test:
it('constructor was called.', () => {
const Foo = require('../app/foo');
const fooModule = module.children.find(m => m.id.includes('foo.js'));
const fooSpy = sinon.spy(fooModule, 'exports');
const f = new Foo(5);
expect(fooSpy).calledOnce;
});
Function to be instantiated:
const Foo = function(param) {
console.log('Foo called with: ' + param);
};
Foo.prototype.bar = function(x) {
console.log(`Foo.prototype.bar() called with x: ` + x);
};
module.exports = Foo;
When I step with debugger I can see the function at const fooSpy = sinon.spy(fooModule, 'exports'); being replaced by the spy (has all all sinon properties added like calledOnce and so on...) however when on new Foo(5); it appears that Foo is a non spy object.
I thought this might be a scoping or reference error but I can't seem to find where else Foo would be defined apart from within module.children. It is not on global neither its on window since its running on node.
Currently the test of course fails with:
Foo called with: 5
AssertionError: expected exports to have been called exactly once, but it was called 0 times
at Context.it (test/fooTest.js:18:23)
Thanks in advance for any help!
Your issue is not really with the sinon.spy API, but with how Node modules import functions. When calling sinon.spy, unless we are testing a callback function, we usually need an Object to be the context on which we want to spy on a particular method. This is why your example tries to access the exports Object of the foo.js module. I am not aware of Node giving us access to such an Object.
However, for your example to work, we don't need access to the Foo module's exports, we could simply create a context of our own. For example:
const chai = require("chai");
const sinon = require("sinon");
const sinonChai = require("sinon-chai");
const expect = chai.expect;
chai.use(sinonChai);
describe("foo", function () {
it('constructor was called.', function () {
const context = {
Foo: require("../app/foo"),
};
const fooSpy = sinon.spy(context, "Foo");
new context.Foo(5);
expect(fooSpy).to.be.calledOnceWith(5);
});
});
Of course, the above test is a working solution to the problem provided in your example, but, as a test, it is not very useful because the assertion just verifies the line above it.
Spies are more useful when they are dependencies of the System Under Test (SUT). In other words, if we have some module that is supposed to construct a Foo, we want to make the Foo constructor a Spy so that it may report to our test that the module did indeed call it.
For example, let's say we have fooFactory.js module:
const Foo = require("./foo");
module.exports = {
createFoo(num) {
return new Foo(num);
},
};
Now we would like to create a unit-test that confirms that calling the createFoo function of the fooFactory.js module calls the Foo constructor with the specified argument. We need to override fooFactory.js's Foo dependency with a Spy.
This returns us to our original problem of how can we turn an imported (constructor) Function into a spy when it is not a method on a context Object and so we cannot overwrite it with sinon.spy(context, 'method').
Fortunately, we are not the first ones to encounter this problem. NPM modules exist that allow for overriding dependencies in required modules. Sinon.js provides a How-To on doing this sort of thing and they use a module called proxyquire.
proxyquire will allow us to import the fooFactory.js module into our unit-test, but also (and more importantly) to override the Foo that it depends on. This will allow our unit-test to make fooFactory.js use a sinon.spy in place of the Foo constructor.
The test file becomes:
const chai = require("chai");
const proxyquire = require("proxyquire");
const sinon = require("sinon");
const sinonChai = require("sinon-chai");
const expect = chai.expect;
chai.use(sinonChai);
describe("fooFactory", function () {
it("calls Foo constructor", function () {
const fooSpy = sinon.spy();
const { createFoo } = proxyquire("../app/fooFactory", {
"./foo": fooSpy,
});
createFoo(5);
expect(fooSpy).to.be.calledOnceWith(5);
});
});

Node.js how should I unit test a function calling other functions

I want to unit test a module I've built.
To give an impression of what it looks like pretty much..
MyModule:
function MyModule(...) {
var self = this;
MyModule.init.call(self, ...);
}
util.inherits(MyModule, MySuperModule);
MyModule.init = function(...) {
...
};
MyModule.prototype.logic = function(..., done) {
calls fnA, fnB, fnC, fnD conditionally
done(...)
};
MyModule.prototype.fnA = function(...) {
...
};
MyModule.prototype.fnB = function(...) {
...
};
MyModule.prototype.fnC = function(...) {
...
};
MyModule.prototype.fnD = function(...) {
...
};
MySuperModule:
function MySuperModule(...) {
...
}
MySuperModule.prototype,fn = function(..., done) {
var self = this;
...
self.logic(..., function done(...) {
...
done(...)
});
}
Now MyModule.logic() is never called explicitly by a user, it is only invoked MySuperModule.fn().
Same goes for all other MyModule functions which are called conditionally based on the given parameters being passed through the delegating chain.
My questions are as follow:
Do I need to test all MyModule functions separately or just test MySuperModule.fn() with different parameters covering all possible scenarios
I know I need to test function in isolation (which if I do my previous question is wrong to ask because than I won't really have tested MyModule functions at all), how would I do that with the MySuperModule.fn(), because its done() callback is being called with arguments dependent on what the MyModule.logic() done() callback was called with, which is again, dependent on the arguments supplied to MySuperModule.fn() arguments.
It really depends how you're injecting MyModule on MySuperModule. But first of all I would point out that in unit tests you have to test MyModule separately and MySuperModule with a Mocked version from MyModule and all other dependencies. This is because you don't want to test MyModule twice, no need for that.
So to create stubs there is a library called Sinon.JS which works really fine.
So if for any reason you just want to make a spy to MyModule, which means you are just attaching a listener to MyModule (it is applied to MyModule methods) which counts and tells if a given method is ever called and how.
var MyModuleMethodASpy = sinon.spy(MyModulem 'MethodA');
MySuperModule.someMethod();
assert(MyModuleMethodASpy.called)
So this code creates a spy, triggers some method on MySuperModule and checks if MyModule.MethodA() is ever called.
You can create stubs as well if you want to control what dependencies return on specific methods eg :
var MyModuleStub = sinon.stub(MyModule, 'MethodA').returns([...somedata]);
In my view you should certainly be testing the individual functions, regardless of whether or not they're called directly by a user.
The purpose of unit testing is to try to ensure that the individual units of your test do what they're expected to do. If you're (relatively) sure that your individual functions/units behave as expected, you can have more confidence that they'll work nicely with each other.
It's hard to really glean from your code snippets the nature of your module, so suggesting how to implement your tests is difficult. However, it seems like what you're asking is how to verify whether your done/callback function is called and with which arguments.
For that I would recommend using a stub. I usually use sinon but I'm sure other similar tools are available.
var sinon = require( "sinon" );
var should = require( "chai" ).should();
var yourModule = require( "your-module" );
var doneStub = sinon.stub();
yourModule.yourFunction( ..., doneStub );
doneStub.should.have.been.called;
var args = doneStub.getCall( 0 ).args;
args[ 0 ].should.be.eql( ... );
// etc etc
You should also consider using a test runner, I like mocha!
You should do progressive testing. You should test each and every function.
Here how can you proceed.
Write test case for parent function. Mock the inner function where it is calling. You can use sinon library for mocking.
For second question, you can use sinon mock's yield functionality to mock any callback function and you can specify also which output you want from that callback. In this way you can test your function for multiple custom output with different scenario.

How to spy on a method inside a dependent module using jasmine-node

I am trying to write jasmine tests for a module-(say moduleA) which 'requires' another module-(moduleB).
======> moduleB.js
function moduleBFunction(){
console.log('function inside moduleB is called');
}
======> moduleA.js
var moduleB = require('./moduleB');
function moduleAfunction(input){
if(input){
moduleB.moduleBFunction()
}
}
I want to write a jasmine test case that tests when i call moduleAfunction, is it calling moduleBfunction or not. I tried to write a test using spyOn(). but i am not sure how can i mock a method inside a dependent module. I did some research and found i might be able to use 'rewire' module for this purpose like below
var moduleB = require('../moduleB');
moduleB.__set__('moduleBfunction', moduleBfunctionSpy);
moduleA.__set__('moduleB', moduleB);
it('should call moduleBfunction', function(){
moduleA.moduleAfunction()
expect(moduleB.moduleBfunction()).toHaveBeenCalled()
});
but I feel there should be a simpler way.
Please suggest.
I recommend sinon.js
var sinon = require('sinon')
var moduleA = require('../moduleA')
var moduleB = require('../moduleB')
it('should call moduleBfunction', function() {
var stub = sinon.stub(moduleB, 'moduleBfunction').returns()
moduleA.moduleAfunction()
expect(moduleB.moduleBfunction.calledOnce)
stub.restore()
})
You can easily fake many different behaviours like:
stub throws
stub returns a certain value
stub yields (mimicking async callback)
stub works restricted with just for certain input arguments
Don't forget to restore each stub before executing the next test. It's best to use sandboxes and afterEach / beforeEach
describe('tests which require some fakes', function() {
var sandbox
beforeEach(function() {
sandbox = sinon.sandbox.create()
})
afterEach(function() {
sandbox.restore()
})
})

How stub a global dependency's new instance method in nodejs with sinon.js

Sorry for the confusing title, I have no idea how to better describe it. Let's see the code:
var client = require('some-external-lib').createClient('config string');
//constructor
function MyClass(){
}
MyClass.prototype.doSomething = function(a,b){
client.doWork(a+b);
}
MyClass.prototype.doSomethingElse = function(c,d){
client.doWork(c*d);
}
module.exports = new MyClass();
Test:
var sinon = require('sinon');
var MyClass = requre('./myclass');
var client = require('some-external-lib').createClient('config string');
describe('doSomething method', function() {
it('should call client.doWork()',function(){
var stub = sinon.stub(client,'doWork');
MyClass.doSomething();
assert(stub.calledOnce); //not working! returns false
})
})
I could get it working if .createClient('xxx') is called inside each method instead, where I stub client with:
var client = require('some-external-lib');
sinon.stub(client, 'createClient').returns({doWork:function(){})
But it feels wrong to init the client everytime the method each being called.
Is there a better way to unit test code above?
NEW: I have created a minimal working demo to demonstrate what I mean: https://github.com/markni/Stackoverflow30825202 (Simply npm install && npm test, watch the test fail.) This question seeks a solution make the test pass without changing main code.
The problem arises at the place of test definition. The fact is that in Node.js it is rather difficult to do a dependency injection. While researching it in regard of your answer I came across an interesting article where DI is implemented via a custom loadmodule function. It is a rather sophisticated solution, but maybe eventually you will come to it so I think it is worth mentioning. Besides DI it gives a benefit of access to private variables and functions of the tested module.
To solve the direct problem described in your question you can stub the client creation method of the some-external-lib module.
var sinon = require('sinon');
//instantiate some-external-lib
var client = require('some-external-lib');
//stub the function of the client to create a mocked client
sinon.stub(client, 'createClient').returns({doWork:function(){})
//due to singleton nature of modules `require('some-external-lib')` inside
//myClass module will get the same client that you have already stubbed
var MyClass = require('./myclass');//inside this your stubbed version of createClient
//will be called.
//It will return a mock instead of a real client
However, if your test gets more complicated and the mocked client gets a state you will have to manually take care of resetting the state between different unit tests. Your tests should be independent of the order they are launched in. That is the most important reason to reset everything in beforeEach section
You can use beforeEach() and afterEach() hooks to stub global dependency.
var sinon = require('sinon');
var MyClass = requre('./myclass');
var client = require('some-external-lib').createClient('config string');
describe('doSomething method', function() {
beforeEach(function () {
// Init global scope here
sandbox = sinon.sandbox.create();
});
it('should call client.doWork()',function(){
var stub = sinon.stub(client,'doWork').yield();
MyClass.doSomething();
assert(stub.calledOnce); //not working! returns false
})
afterEach(function () {
// Clean up global scope here
sandbox.restore();
});
})
Part of the problem is here: var stub = sinon.stub(client,'doWork').yield();
yield doesn't return a stub. In addition, yield expects the stub to already have been called with a callback argument.
Otherwise, I think you're 95% of the way there. Instead of re-initializing for every test, you could simply remove the stub:
describe('doSomething method', function() {
it('should call client.doWork()',function(){
var stub = sinon.stub(client,'doWork');
MyClass.doSomething();
assert(stub.calledOnce);
stub.restore();
})
})
BTW, another poster suggested using Sinon sandboxes, which is a convenient way to automatically remove stubs.

node, unit-testing and mocking with sinon

So I am using a test suite of Chai, rewire, sinon, and sinon-chai to test some node javascript. This is my first time trying to set this up so I could use some pointers. The function I am trying to test looks like so :
UserRoles.get = function(ccUrl, namespace, environment, ccToken, authPath) {
var crowdControl = new CrowdControl(ccUrl, namespace, environment, ccToken, authPath);
return q.Promise(function(resolve, reject) {
crowdControl.get().then(resolve).fail(reject).done();
});
};
Inside a document that exports as UserRoles. So I have the initial set up working fine, where I am having troubles is mocking to test this function. I'm trying to mock the new CrowdContol part so my attempt to do that looks like so : https://jsfiddle.net/d5dczyuk/ .
so I'm trying out the
testHelpers.sinon.stub(CrowdControl, "UserRoles");
to intercept and stub
var CrowdControl = require('./crowdcontrol');
then just running
userRoles.get;
console.log(CrowdControl);
And it seems the stub is not being called ( it logs it's a stub but not that it has been called). I will also need to stub the crowdControl.get() hopefully too, however I was trying to get this simple part working first. Not sure what I need to be doing differently to get this to work here. This is my first time unit testing in node, I've done a bunch in angular where I could just "mock" the CrowdControl, but I'm not sure how it works in node.
Just to clarify I am just checking if CrowControl will be called with those vars passing in, should I just stub it? but I also want to mock the crowdControl so I can force what the get returns.
Edit: here is my second attempt : https://jsfiddle.net/5m5jwk5q/
I like to use proxyquire for this kind of testing. With proxyquire you can stub out require'd dependencies from the modules you're trying to test. So in your case you could do:
var crowdControlSpy = sinon.spy();
// Makes sure that when ./user-roles tries to require ./crowdcontrol
// our controlled spy is passed, instead of the actual module.
var UserRoles = proxyquire('./user-roles', {
'./crowdcontrol': crowdControlSpy
});
UserRoles.get(...);
expect(crowdControlSpy).to.have.been.called;

Categories

Resources