I am having issues writing unit test for the following setup as a jira.js file (in a node.js module):
var rest = require('restler'); // https://www.npmjs.com/package/restler
module.exports = function (conf) {
var exported = {};
exported.getIssue = function (issueId, done) {
...
rest.get(uri).on('complete', function(data, response) {
...
};
return exported;
};
Now, i want to write unit test for my getIssue function. 'restler' is a REST client through which i make REST calls to the JIRA API to get a JIRA issue via my code.
So to be able to test createIssue(..), I want to be able to mock the 'rest' var in my Jasmine unit tests.
How can i mock this method? Please give me some pointers so that i can go ahead. I have tried using rewire but i have failed.
This is what i have so far which does not work (ie. getIssue method turns out to be undefined):
var rewire = require("rewire");
var EventEmitter = require('events').EventEmitter;
var emitter = new EventEmitter();
var cfg = require("../../../config.js").Configuration;
var jiraModule = rewire("../lib/jira")(cfg);
var sinon = require("sinon");
var should = require("should");
// https://github.com/danwrong/restler
var restMock = {
init : function () {
console.log('mock initiated'+JSON.stringify(this));
},
postJson : function (url, data, options) {
console.log('[restler] POST url='+url+', data= '+JSON.stringify(data)+
'options='+JSON.stringify(options));
emitter.once('name_of_event',function(data){
console.log('EVent received!'+data);
});
emitter.emit('name_of_event', "test");
emitter.emit('name_of_event');
emitter.emit('name_of_event');
},
get : function (url, options) {
console.log('[restler] GET url='+url+'options='+JSON.stringify(options));
},
del : function (url, options) {
console.log('[restler] DELETE url='+url+'options='+JSON.stringify(options));
},
putJson : function (url, data, options) {
console.log('[restler] PUT url='+url+', data= '+JSON.stringify(data)+
'options='+JSON.stringify(options));
}
};
var cfgMock = {
"test" : "testing"
};
jiraModule.__set__("rest", restMock);
jiraModule.__set__("cfg", cfgMock);
console.log('mod='+JSON.stringify(jiraModule.__get__("rest")));
describe("A suite", function() {
it("contains spec with an expectation", function() {
restMock.init();
restMock.postJson(null, null, null);
console.log(cfg.jira);
// the following method turns out to be undefined but when i console.log out the jiraModule, i see the entire code outputted from that file
jiraModule.getIssue("SRMAPP-130", function (err, result) {
console.log('data= '+JSON.stringify(result));
});
expect(true).toBe(true);
});
});
If someone can guide me on how to mock the 'rest' require dependency & unit test this method that will be very helpful.
Also, how should i mock the 'conf' being passed to module.exports?
thanks
You could use proxyquire or mockery to stub/mock the dependencies.
In the below example I have used proxyquire. Hope it helps.
/* ./src/index.js */
var rest = require('restler');
module.exports = function (conf) {
var exported = {};
exported.getIssue = function (issueId, done) {
var uri = '';
var reqObj = '';
var service = {
auth : ''
};
rest.postJson(uri, reqObj, service.auth).on('complete', function(data, response) {
done(data, response);
});
};
return exported;
};
/* ./test/index.js */
var proxyquire = require('proxyquire');
var assert = require('chai').assert;
var restlerStub = {
postJson: function() {
return {
on: function(event, callback) {
callback('data', 'response');
}
}
}
}
var index = proxyquire('../src/index', {'restler': restlerStub})();
describe('index', function() {
it('should return the desired issue', function(done) {
var issue = index.getIssue('issueId', function(data, response) {
assert.equal(data, 'data');
assert.equal(response, 'response');
done();
})
});
});
/* ./package.json */
{
"scripts": {
"test": "mocha"
},
"dependencies": {
"restler": "^3.4.0"
},
"devDependencies": {
"chai": "^3.4.1",
"mocha": "^2.3.4",
"proxyquire": "^1.7.3"
}
}
Related
Trying to write a unittest for the below module in /utility/sqsThing.js. However I'm having diffuculty mocking the sqs.sendMessage method. Anyone know how I should go about this. I'm using the sinon library, and mocha for running the tests.
The function that I'm trying to unittest utility/sqsThing.js:
const AWS = require('aws-sdk');
AWS.config.update({ region: 'us-east-1' });
const sqs = new AWS.SQS({ apiVersion: '2012-11-05' });
const outputQueURL = 'https:awsUrl';
const SQSOutputSender = (results) => {
const params = {
MessageBody: JSON.stringify(results),
QueueUrl: outputQueURL,
};
// Method that I want to mock
sqs.sendMessage(params, function (err, data) {
if (err) {
console.log('Error');
} else {
console.log('Success', data.MessageId);
}
});
};
My attempt at mocking the sqs.sendMessage method in a unittest sqsThingTest.js:
const sqsOutputResultSender = require('../utility/sqsThing');
const AWS = require('aws-sdk');
const sqs = new AWS.SQS({ apiVersion: '2012-11-05' });
const mochaccino = require('mochaccino');
const { expect } = mochaccino;
const sinon = require('sinon');
describe('SQS thing test', function() {
beforeEach(function () {
sinon.stub(sqs, 'sendMessage').callsFake( function() { return 'test' });
});
afterEach(function () {
sqs.sendMessage.restore();
});
it('sqsOutputResultSender.SQSOutputSender', function() {
// Where the mock substitution should occur
const a = sqsOutputResultSender.SQSOutputSender('a');
expect(a).toEqual('test');
})
});
Running this unittest with mocha tests/unit/sqsThingTest.js however I get:
AssertionError: expected undefined to deeply equal 'test'.
info: Error AccessDenied: Access to the resource https://sqs.us-east-1.amazonaws.com/ is denied..
It looks like the mock did not replace the aws api call. Anyone know how I can mock sqs.SendMessage in my test?
You could use rewire js it is a library that lets you inject mocked properties into your module you want to test.
Your require statement would look something like this:
var rewire = require("rewire");
var sqsOutputResultSender = rewire('../utility/sqsThing');
Rewire will allow you to mock everything in the top-level scope of you sqsThing.js file.
Also you need to return the value of sqs.sendMessage this will remove the issue expected undefined to deeply equal 'test'
Your original file would look the same just with a return statement.
//utility/sqsThing.js
const AWS = require('aws-sdk');
AWS.config.update({ region: 'us-east-1' });
const sqs = new AWS.SQS({ apiVersion: '2012-11-05' });
const outputQueURL = 'https:awsUrl';
const SQSOutputSender = (results) => {
const params = {
MessageBody: JSON.stringify(results),
QueueUrl: outputQueURL,
};
// Method that I want to mock
return sqs.sendMessage(params, function (err, data) {
if (err) {
console.log('Error');
} else {
console.log('Success', data.MessageId);
}
});
};
You would then write your unit test as follows:
//sqsThingTest.js
var rewire = require("rewire");
var sqsOutputResultSender = rewire('../utility/sqsThing');
const mochaccino = require('mochaccino');
const { expect } = mochaccino;
const sinon = require('sinon');
describe('SQS thing test', function() {
beforeEach(function () {
sqsOutputResultSender.__set__("sqs", {
sendMessage: function() { return 'test' }
});
});
it('sqsOutputResultSender.SQSOutputSender', function() {
// Where the mock substitution should occur
const a = sqsOutputResultSender.SQSOutputSender('a');
expect(a).toEqual('test');
})
});
This example returns an object with a property of sendMessage but this could be replaces with a spy.
Rewire Docs
Try moving the declaration of sqsOutputResultSender after you have stubbed the sendmessage function
var sqsOutputResultSender;
const AWS = require('aws-sdk');
const sqs = new AWS.SQS({ apiVersion: '2012-11-05' });
const mochaccino = require('mochaccino');
const { expect } = mochaccino;
const sinon = require('sinon');
describe('SQS thing test', function() {
beforeEach(function () {
sinon.stub(sqs, 'sendMessage').callsFake( function() { return 'test' });
sqsOutputResultSender = require('../utility/sqsThing');
});
afterEach(function () {
sqs.sendMessage.restore();
});
it('sqsOutputResultSender.SQSOutputSender', function() {
// Where the mock substitution should occur
const a = sqsOutputResultSender.SQSOutputSender('a');
expect(a).toEqual('test');
})
});
I'm trying to use proxyquire to stub the spawnSync method of the child_process module, but it doesn't work. The console.log(gitResponse) in my index.js file doesn't return the stubbed string, but the unstubbed response (in this case, the git help text).
Can someone see what I am doing wrong?
/index.js
var childProcess = require('child_process');
function init () {
var gitInit = childProcess.spawnSync('git', ['init']);
var gitResponse = gitInit.stdout.toString() || gitInit.stderr.toString();
console.log(gitResponse);
}
module.exports = {
init: init
}
/test/indexTest.js
var assert = require('assert');
var index = require('../index.js');
var sinon = require('sinon');
var proxyquire = require('proxyquire');
describe('test', function () {
it('tests', function () {
var spawnSyncStub = function (command, args) {
return {
stdout: {
toString: () => "git init success string"
}
};
};
proxyquire('../index.js', {
'child_process': {
spawnSync: spawnSyncStub
}
});
index.init();
}
}
According to the documentation; should you not be doing something like this:?
var assert = require('assert');
var index = proxyquire('../index.js', {
'child_process': {
spawnSync: function (command, args) {
return {
stdout: {
toString: () => "git init success string"
}
};
}
}
});
var sinon = require('sinon');
var proxyquire = require('proxyquire');
describe('test', function () {
it(
'tests'
,function () {
sinon.assert.match(index.init(), "git init success string");
}
)
});
I am using Swagger Node with express and I initialized the skeleton project. Swagger project create hello-world
Then inside the hello-world/api/controllers/hello_world.js I added a small modification to require a helper hello_helper.js and call its function helloHelper.getName().
'use strict';
let helloHelper = require('../helpers/hello_helper');
var util = require('util');
module.exports = {
hello: hello
};
function hello(req, res) {
var name = req.swagger.params.name.value || helloHelper.getName();
var hello = util.format('Hello, %s!', name);
res.json(hello);
}
hello-world/api/helpers/hello_helper.js
'use strict';
module.exports = {getName: getName};
function getName() {
return 'Ted';
}
I would like to stub helloHelper.getName() to return 'Bob' instead.
I can do so easily with:
hello-world/test/api/controllers/hello_world.js
// Create stub import of hello_helper
mockHelloHelper = proxyquire('../../../api/controllers/hello_world', { '../helpers/hello_helper': { getName: function () { return 'Bob'; } }
});
Using supertest how can I make swagger recognize my stub?
EDIT: Thanks to help from the answer below this solution worked for me.
var app, getNameStub, mockHelloHelper, request;
beforeEach(function (done) {
// Create stub import of hello_helper
mockHelloHelper = proxyquire('../../../api/controllers/hello_world', {
'../helpers/hello_helper': {
getName: function () {
return 'Bob';
}
}
});
app = require('../../../app');
request = supertest(app);
done();
});
...
it('should return a default string', function(done) {
request
.get('/hello')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res) {
should.not.exist(err);
res.body.should.eql('Hello, Bob!');
done();
});
});
You need to initialize/require express app after you have proxyquired your dependency. Only then it can use your stubbed version of getName:
beforeEach(function () {
mockHelloHelper = proxyquire('../../../api/controllers/hello_world', {
'../helpers/hello_helper': {
getName: function () {
return 'Bob';
}
}
});
// initialize/require your app here
request = supertest(app);
});
Module under test:
'use strict';
const config = require('config');
const q = require('q');
class RedisAccess {
static getValue(key) {
let deferred = q.defer();
if (config.redis.disableInteraction) {
deferred.resolve();
return deferred.promise;
}
config.redisClient.get(key, function handleResults(err, result) {
...
return deferred.promise;
}
}
exports = module.exports = RedisAccess;
Test:
var proxyquire = require('proxyquire').noPreserveCache();
var assert = require('assert');
var readdirError = new Error('some error');
var redisClientStub = { };
var calledBack;
// Override redisClient used by RedisAccess.js.
var redisClientProxy = proxyquire('../../../lib/data/redis/RedisAccess.js', { 'config' : redisClientStub });
// Test redisClient.get(...) to retrieve value given key using proxyquire for redisClient.
redisClientStub.redisClient.get = function (key, cb) {
cb(null, 'hello world');
};
calledBack = false;
// Test redisClient getValue async function.
redisClientProxy.getValue('some_key', function (err, value) {
assert.equal(err, null);
assert.equal('value', 'hello world');
callback = true;
});
The error when I execute the test is:
redisClientStub.redisClient.get = function (key, cb) {
^
TypeError: Cannot set property 'get' of undefined
How do I properly stub the config.redisClient.get(...) function?
I figured this out. I had to put a "stub within a stub" to stub the config.redisClient.get() function:
// Proxyquire allows unobstrusively overriding dependencies during testing.
// Override config used by RedisAccess.js.
var configStub = {
redisClient : {
createClient : function (port, address) {
// redis-mock-js used instead.
},
get : function (key, cb) {
if(key === 'test-rejected') {
cb(new Error('test-rejected'), 'rejected-promise');
}
else if(key === 'test-true') {
cb(null, true);
}
else if(key === 'test-get-valid') {
cb(null, 'valid-value');
}
else {
cb(new Error('Should not have gotten here!'), 'value');
}
},
}
};
which allowed me to construct this proxyquire:
var redisAccessProxy = proxyquire('lib/data/redis/RedisAccess.js', { 'config' : configStub });
and run this test using a proxy function for redisClient.get(...) which is called inside of RedisAccess.getValue(...):
var val = redisAccessProxy.getValue('test-get-valid');
assert.equal(val.isFulfilled(), true);
assert.equal(val.isRejected(), false);
assert.equal(val, 'valid-value');
I have a simple AWS Node.js Lambda, which I would like to test using mocks:
//SimpleLambda.js
var AWS = require('aws-sdk');
exports.handler = function(event, context) {
var name = getName();
context.succeed(name);
};
function getName() {
return 'David';
}
I've installed mocha and simple-mock, but I am unable to get this to work:
//test.js
//Mocha
var assert = require('assert');
//Chai
var chai = require('chai');
var expect = chai.expect;
var should = chai.should();
//Simple-Mock
var simple = require('simple-mock');
//Lambda
var lambda = require('../SimpleLambda');
describe('SimpleLambda tests', function() {
describe('Get name', function() {
beforeEach(function() {
simple.mock(lambda, 'getName');
});
it('should return \'Tim\' when the mocked with simple-mock', function() {
lambda.getName.returnWith('Tim');
var context = {
invokeid: 'invokeid',
succeed: function(result) {
expect(result).to.equal("Tim");
return result;
}
};
lambda.handler({}, context);
});
});
});
Output still suggests getName returns 'David'
SimpleLambda tests
Get name
1) should return 'Tim' when the mocked with simple-mock
0 passing (11ms)
1 failing
1) SimpleLambda tests Get name should return 'Tim' when the mocked with simple-mock:
AssertionError: expected 'Succesfully retrieved: David' to equal 'Tim'
+ expected - actual
-Succesfully retrieved: David
+Tim
at Object.context.succeed (test/test.js:27:29)
at Object.exports.handler (SimpleLambda.js:5:11)
at Context.<anonymous> (test/test.js:32:14)
Can this be done?
You need to export your getName function so that it's accessible from test.js (and can be wrapped by your mocking library).
Something like this:
//SimpleLambda.js
var AWS = require('aws-sdk');
exports.handler = function(event, context) {
var name = exports.getName();
context.succeed(name);
};
exports.getName = function (){
return 'David';
}
Try to put simple.mock(lambda, 'getName').returnWith('Tim'); to beforeEach and delete this lambda.getName.returnWith('Tim');.