node, unit-testing and mocking with sinon - javascript

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;

Related

Jasmine spyOn and how to use spies generally

I am starting out in JS unit testing and having a hard time getting my head around how to create meaningful tests with Jasmine spies.
it('should take an array of shopping items', function() {
spyOn(checkObj, 'getTotal');
checkObj.getTotal([1, 2, 3]);
expect(checkObj.getTotal).toHaveBeenCalledWith(jasmine.any(Array));
});
Using the above excerpt of test I created as an example I cant see how this is a useful test as my call to getTotal is hard coded inside the spec. But at the same time I would like to ensure the param passed is an array and not some other type...its the hard coding that I am sure is wrong somehow.
Could someone offer a bit of guidance on how I should think/approach this type of testing scenario
Well, spies are useful for a bit different scenario. Much depends on how you yourself define the scope of your unit test as well. If you do the minimal possible unit (i.e. method) then lets imagine the following:
var x = function() { }
x.prototype.f1 = function() {
//do something
},
x.prototype.f2 = function(){
// do something else
this.f1();
}
Now, in your unit test for f2 you are not interested in how f1 works inside. so, you make a spy on it:
var a = new x();
a.f1 = jasmine.createSpy("spy-on-f1");
expect(a.f1).not.toHaveBeenCalled();
a.f2();
expect(a.f1).toHaveBeenCalled();
For example, for angularjs applications, I often mock whole services with spies, just to isolate the algorithm in testing.
As a bonus, you can actually replace the real call with some fake function like this:
a.f1 = jasmine.createSpy("fake-spy").and.callFake(function(){
// do something predictible or return global variable that can be set externaly
});

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 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.

Jasmine-node - Creating a spy on a constructor called inside other function

I'm novice in jasmine and I need to write some unit tests for node.js app in this framework.
I have some problems, one of them is this described below:
var sampleFunction = function(){
var loader = new Loader(params);
// rest of logic here
}
I want to write unit test for sampleFunction. To do this I need to create spy on Loader constructor and check what this constructor gets as params and what kind of object is it returning.
Any ideas how to do that? I tried to create spy on Loader.prototype.constructor but it wasn't a solution to this problem.
OK, so normally in client-side JavaScript you would use the window object like so jasmine.spyOn(window, 'Loader')
In node, however, there is no window object and despite claims to the contrary global is not a substitute (unless you are in the REPL which runs in global scope).
function MyConstructor () {}
console.log(global.MyConstructor); --> undefined
console.log(this.MyConstructor); --> undefined
So, in node you need to attach your constructor to an object. So just do something like this
var Helpers = {
Loader: Loader
};
var constSpy = jasmine.spyOn(Helpers, 'Loader').andCallThrough();
sampleFunction();
expect(constSpy).toHaveBeenCalled();
The andCallThrough call is only necessary if you want your constructor to do something (often with constructor you do).
This is a little hacky, but it works and seems to be the only way to achieve this through jasmine's implementation within node.

How can i use sinon to stub functions for neo4j Thingdom module

I am having some issues writing some unit tests where i would like to stub out the functionality of the neo4j Thingdom module.
After a few hours of failed attempts i have been searching around the web and the only point of reference i found was a sample project which used to sinon.createStubInstance(neo4j.GraphDatabase); to stub out the entire object. For me, and becuase this seemed to a be a throw away project i wanted a more fine grained approach so i can test that for instance as the Thingdom API outlines when saving a node you create it (non persisted) persist it and then you can index it if you wish which are three calls and could be outlined in multiple specific tests, which i am not sure can be achieved with the createStubInstance setup (i.e. found out if a function was called once).
Example "create node" function (this is just to illustrate the function, i am trying to build it out using the tests)
User.create = function(data, next){
var node = db.createNode(data);
node.save(function(err, node){
next(null,node);
});
};
I am able to stub functions of the top level object (neo4j.GraphDatabase) so this works:
it('should create a node for persistence', function(){
var stub = sinon.stub(neo4j.GraphDatabase.prototype, 'createNode');
User.create({}, res);
stub.calledOnce.should.be.ok;
stub.restore();
});
The issue comes with the next set of test i wish to run which tests if the call to persist the node to the database is called (the node,save) method:
I am not sure if this is possible or it can be achieved but i have tried several variations of the stub and non seem to work (on neo4j.Node, neo4j.Node.prototype) and they all come back with varying errors such as can't wrap undefined etc. and this is probably due to the createNode function generating the node and not my code directly.
Is there something i am glaringly doing wrong, am i missing the trick or can you just not do this? if not what are the best tactics to deal with stuff like this?
A possible solution is to return a stubbed or mocked object, giving you control on what happens after the node is created:
it('should create a node for persistence and call save', function () {
var stubbedNode = {
save: sinon.stub().yields(undefined, stubbedNode)
};
var stub = sinon.stub(neo4j.GraphDatabase.prototype, 'createNode').returns(stubbedNode);
User.create({}, res);
stub.calledOnce.should.be.ok;
stub.restore();
stubbedNode.save.calledOnce.should.be.ok;
});
We couldn't do it directly, the way the module is setup it doesn't work to well with Sinon. What we are doing is simply abstracting the module away and wrapping it in a simple facade/adapter which we are able to stub on our unit tests.
As we are not doing anything bar calling the neo4j module in that class we are integration (and will validate when regression testing) testing that part to make sure we are hitting the neo4j database.

Categories

Resources