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

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.

Related

Test that a function calls another function in an ES6 module with Sinon.js

I want to test that a function in an ES6 module calls another function using Sinon.js. Here's the basic layout of what I'm doing:
foo.js
export function bar() {
baz();
}
export function baz() {
...
}
test.js
import sinon from 'sinon';
import * as Foo from '.../foo';
describe('bar', function() {
it('should call baz', function() {
let spy = sinon.spy(Foo, 'baz');
spy.callCount.should.eql(0);
Foo.bar();
spy.calledOnce.should.eql(true);
});
});
But the spy does not pick up the call to baz(). Is there some other way I can set up the module or the test to allow sinon to pick this up? My alternative is to make some basic assertion on something baz does, but I obviously don't want to be doing that.
From what I've seen online I'm wondering if this is even possible with the code laid out as-is or if I need to restructure it to get what I want.
You're right in thinking this isn't possible with the way the module is currently structured.
When the code is executed, the baz reference inside function bar is resolved against the local implementation. You can't modify that since outside of the module code there's no access to the internals.
You do have access to exported properties, but you can't mutate these and so you can't affect the module.
One way to change that is using code like this:
let obj = {};
obj.bar = function () {
this.baz();
}
obj.baz = function() {
...
}
export default obj;
Now if you override baz in the imported object you will affect the internals of bar.
Having said that, that feels pretty clunky. Other methods of controlling behaviors exist such as dependency injection.
Also, you should consider whether or not you actually care if baz was called. In standard "black-box testing", you don't care how something is done, you only care what side effects it generated. For that, test if the side effects you expected happened and that nothing else was done.

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;

JS: replace function definition before object instantiation

I have outerView and innerView inside my require.js module. They can be described with few statements:
InnerViews is instantiated on OuterView rendering
InnerView calls calculated method on own instantiation
InnerView.calculate method use AJAX, which is undesirable in unit tests (with jasmine)
I need: in my jasmine tests replace innerView.calculate method call with direct call to innerView.handleResults with hardcoded data argument.
Problem: The problem is also that in tests I have access only to outerView. So I need to replace innerView.calculate method definition before the innerView is instantiated.
Question: How to replace innerView.calculated method definition before innerView is instantiated?
Code:
define(".....", function(...) {
var innerView = Backbone.View.extend ({
initialize: function() {
......
calculate(opitons);
},
//I NEED TO REPLACE THIS WITH handleResults(hardcodedData)
calculate: function(options) {
var $this = this;
Utils.doSmth(options).then(
$this.handleResults
);
},
handleResults: function(data) {
....
}
});
var outerView = Backbone.View.extend ({
subViews: [],
render: function() {
subViews[0] = new innerView();
}
});
return outerView;
}
Keep in mind that the BDD philosophy is to test behavior. Ask yourself, do you really want to change how your functions work in your unit tests? By providing an alternate code path, you aren't testing the actual behavior you'll see in production.
For example, what if in your then function you do more complex data massaging than simply calling handleResults(...)? You then need to bring knowledge of this logic into your unit tests so you can mock out the rest of the chain correctly.
It sounds to me like what you really need is a way of mocking the AJAX request, not a way of changing how your code works. There are several ways to accomplish this. Two of the most popular are:
jasmine-ajax -- jasmine-specific
Sinon.JS -- standalone framework for creating spies, mocks, and mock HTTP servers.
I have used Sinon.JS quite a lot for testing XHR-related code paths to great effect.
That looks like a design problem to me. You have a hard-coded dependency on the innerView type in your outerView, and you are hiding it inside a closure (aka module). Worse, that inner, hard-coded dependency is hooked up to the rest of the universe (AJAX call). You'll have to expose the inner view somehow in order to make it testable.
It seems to me that at the very least, you have to open up your outerView like this:
var outerView = Backbone.View.extend ({
subViews: [],
initialize: function (options) {
this.innerView = innerView;
}
render: function() {
subViews[0] = new this.innerView();
}
});
That way, you can at least modify outerview.innerView in your tests before you call render.
And at that point, it is only a small additional step to actually inject the dependency in initialize, perhaps with a default (this.innerView = options && options.innerView || innerView;), if you ever feel the need.

Revealing Module Pattern - Unit Testing with Jasmine

After a brief romance with the revealing module pattern I've come to realise a set-back when it comes to unit-testing modules. I cannot however decide if it is my approach to testing a module or whether there is some form of work-around.
Consider the following code:
var myWonderfulModule = (function () {
function publicMethodA (condition) {
if(condition === 'b') {
publicMethodB();
}
}
function publicMethodB () {
// ...
}
return {
methodA : publicMethodA,
methodB : publicMethodB
}
}());
If I wanted to test (using Jasmine) the various paths leading through publicMethodA to publicMethodB. I might write a small test like so:
it("should make a call to publicMethodB when condition is 'b'", function() {
spyOn(myWonderfulModule , 'publicMethodB');
myWonderfulModule.publicMethodA('b');
expect(myWonderfulModule.publicMethodB).toHaveBeenCalled();
});
If I understand correctly, there's a copy of publicMethodB within the closure that cannot be changed. Even if I change myWonderfulModule.publicMethodB afterwards:
myWonderfulModule.publicMethodB = undefined;
calling myWonderfulModule.publicMethodA will still run the original version of B.
The example above is of course simplified but there are plenty of scenarios I can think of where it would be convenient to unit test conditional paths through a method.
Is this a limitation of the revealing module pattern or simply a misuse of unit testing? If not what work-arounds are available to me? I'm considering moving to something like RequireJS or reverting back to non-modular code.
Any advice appreciated!
You cant test the intern methodes of a closure. And you also shouldn't spy on it. Think about about your module as a black box. You put something in and you get something out. All you should test is that the thing you get out of your module is the one that you expect.
Spying on methodes in your module makes not much sense. Think about it. You spy on it, the test passes. Now you change the functionality so it creates a bug, the test still passes cause the function is still called but you never mention the bug. If you just test the thing that cames out you dont need to spy on internal methodes cause, that they are called is implicite when the outcome of the module is what you expect.
So in your case there is no thing that goes in and nothing comes out. This makes not much sense but I believe that your module interacts with DOM or makes an ajax call. This are things that you can test (DOM) or you should spy on (ajax).
You should also make you self familiar with Inversion of Control and Dependency Injection. These are patterns that will make your modules much more easier to test.
If you use the keyword "this" when you call publicMethodB() from publicMethodA() it will work. For example:
var myWonderfulModule = (function () {
function publicMethodA (condition) {
if(condition === 'b') {
this.publicMethodB();
}
}
function publicMethodB () {
// ...
}
return {
methodA : publicMethodA,
methodB : publicMethodB
}
}());

Categories

Resources