How to stub node-cache's cache.get()? - node.js

I'm writing a unit test for a function that uses node-cache.
At the following function,
I want to have a string return at the first cache.get
an array in the second cache.get
Please note that I removed some parts of code from testFunction since it is not relavant to my question.
const NodeCache = require('node-cache');
const cache = new NodeCache();
...
const testFunction = () => {
let myStringCache = cache.get('cacheName1');
let myArrayCache = cache.get('cacheName2');
... Do something with caches ...
return 'return something';
}
...
module.exports = {
...,
testFunction,
...
}
I created the following test
describe('sample test with testFunction() ', ()=>{
let stubCache;
let stub;
before((done)=>{
sandbox = sinon.createSandbox();
stubCache = sandbox.stub(cache, 'get');
stubCache.withArgs('cacheName1').returns('sample string');
stubCache.withArgs('cacheName2').returns([1,2,3,4,5,6]);
stub = proxyquire('./filelocation.js',{
'node-cache': stubCache
});
done();
});
it('should not throw error',(done)=>{
chai.expect(stub.testFunction()).not.to.throw;
});
})
I was Googling around, and there is some partial solution to use proxyquire to stub the value. but looks like it does stub but it's not where I wanted.
It stubs at NodeCache but cache
So I have questions:
Does anybody know how to stub cache.get() with mocha, chai or sinon? If so, please share how you do it ?
Is it possible to stub different returns by the argument of cache.get()?

Here is the unit test solution:
index.js:
const NodeCache = require("node-cache");
const cache = new NodeCache();
const testFunction = () => {
let myStringCache = cache.get("cacheName1");
let myArrayCache = cache.get("cacheName2");
console.log("myStringCache:", myStringCache);
console.log("myArrayCache:", myArrayCache);
return "return something";
};
module.exports = {
testFunction
};
index.spec.js:
const sinon = require("sinon");
const proxyquire = require("proxyquire");
const chai = require("chai");
describe("sample test with testFunction() ", () => {
let stubCache;
let stub;
let getCacheStub;
before(() => {
sandbox = sinon.createSandbox();
getCacheStub = sandbox.stub();
stubCache = sandbox.stub().callsFake(() => {
return {
get: getCacheStub
};
});
getCacheStub.withArgs("cacheName1").returns("sample string");
getCacheStub.withArgs("cacheName2").returns([1, 2, 3, 4, 5, 6]);
stub = proxyquire("./", {
"node-cache": stubCache
});
});
it("should not throw error", () => {
const logSpy = sinon.spy(console, "log");
chai.expect(stub.testFunction()).not.to.throw;
sinon.assert.calledWith(
logSpy.firstCall,
"myStringCache:",
"sample string"
);
sinon.assert.calledWith(logSpy.secondCall, "myArrayCache:", [
1,
2,
3,
4,
5,
6
]);
});
});
Unit test result with 100% coverage:
sample test with testFunction()
myStringCache: sample string
myArrayCache: [ 1, 2, 3, 4, 5, 6 ]
✓ should not throw error
1 passing (87ms)
---------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
---------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.js | 100 | 100 | 100 | 100 | |
index.spec.js | 100 | 100 | 100 | 100 | |
---------------|----------|----------|----------|----------|-------------------|
Source code: https://github.com/mrdulin/mocha-chai-sinon-codelab/tree/master/src/stackoverflow/58278211

Related

Spy module.exports functions with sinon in NodeJS always returning 0

I am trying to track the number of calls to another function using a test case written with Sinon. I have the following code, and on running the test, the calledFuncSpy callCount always gets me 0, which is not expected. Meanwhile, running another spy on console.log gives me the correct output, and I have left it commented in the code. Does anyone know what could be the problem?
Here’s the code. Let me know if more information is required to solve this problem.
specs/mymodule.js
const mymodule = require("../src/mymodule.js");
var sinon = require("sinon");
const assert = require("assert");
describe("Test suite", function() {
let calledFuncSpy;
let consoleSpy;
beforeEach(function () {
calledFuncSpy = sinon.spy(mymodule, "calledFunc");
consoleSpy = sinon.spy(console, "log");
})
afterEach(function () {
calledFuncSpy.restore();
consoleSpy.restore();
})
it("Test the add method", function () {
mymodule.ownHelloWorld();
assert.deepStrictEqual(calledFuncSpy.callCount, 1);
// assert.deepStrictEqual(consoleSpy.callCount, 1);
});
})
src/mymodule.js
function ownHelloWorld() {
calledFunc();
}
function calledFunc() {
console.log("Hello world");
}
module.exports = {
ownHelloWorld,
calledFunc
}
calledFunc called inside ownHelloWorld function can NOT be stubbed. It will always use the original calledFunc function. sinon.spy(mymodule, "calledFunc") can NOT modify the reference of it when calling the ownHelloWorld function. Also, see this comment
You can refactor it like this:
mymodule.js:
function ownHelloWorld() {
module.exports.calledFunc();
}
function calledFunc() {
console.log('Hello world');
}
module.exports = {
ownHelloWorld,
calledFunc,
};
mymodule.test.js:
const mymodule = require('./mymodule');
var sinon = require('sinon');
describe('Test suite', function () {
let calledFuncSpy;
let consoleSpy;
beforeEach(function () {
calledFuncSpy = sinon.spy(mymodule, 'calledFunc');
consoleSpy = sinon.spy(console, 'log');
});
afterEach(function () {
calledFuncSpy.restore();
consoleSpy.restore();
});
it('Test the add method', function () {
mymodule.ownHelloWorld();
sinon.assert.calledOnce(calledFuncSpy);
});
});
test result:
Test suite
Hello world
✓ Test the add method
1 passing (5ms)
-------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
mymodule.js | 100 | 100 | 100 | 100 |
-------------|---------|----------|---------|---------|-------------------

How to mock nested dependencies in NodeJS

I have a Module a
const b = require(./b);
function aGetResult() {
return b.getInfo();
}
Module B
const c = require(./c);
function getInfo() {
return getDetailInfo();
}
function getDetailInfo() {
const result = c.getApiResult();
return result
}
Module C
function getApiResult() {
return api.get(/test/1);
}
I've written a test for module A but am running into an issue with stubbing dependencies.I just want to stub c.getApiResult() and not b.getInfo() or b.getDetailInfo(). I've tried selectively stubbing using proxyquire but am having issues. Any help?
You should use Globally override require of proxyquire package.
a depends b, b depends on c. Now you want to mock the indirect c dependency instead of direct b dependency when you test a. It's NOT recommended to do this. But anyway, here is the solution:
E.g.
a.js:
const b = require('./b');
function aGetResult() {
return b.getInfo();
}
exports.aGetResult = aGetResult;
b.js:
const c = require('./c');
function getInfo() {
return getDetailInfo();
}
function getDetailInfo() {
const result = c.getApiResult();
return result;
}
module.exports = { getInfo };
c.js:
const api = {
get(url) {
return 'real result';
},
};
function getApiResult() {
return api.get('/test/1');
}
module.exports = { getApiResult };
a.test.js:
const proxyquire = require('proxyquire');
const { expect } = require('chai');
const sinon = require('sinon');
describe('63275147', () => {
it('should pass', () => {
const stubs = {
'./c': {
getApiResult: sinon.stub().returns('stubbed result'),
'#global': true,
},
};
const a = proxyquire('./a', stubs);
const actual = a.aGetResult();
expect(actual).to.be.eq('stubbed result');
sinon.assert.calledOnce(stubs['./c'].getApiResult);
});
});
unit test result:
63275147
✓ should pass (2630ms)
1 passing (3s)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 83.33 | 100 | 60 | 83.33 |
a.js | 100 | 100 | 100 | 100 |
b.js | 100 | 100 | 100 | 100 |
c.js | 50 | 100 | 0 | 50 | 3-8
----------|---------|----------|---------|---------|-------------------

How to use sinon to stub aws-param-store getParametersByPath()

I'm using the package aws-param-store and I'm trying to write Unit tests
that stub calls to getParametersByPath().
Package can be found here:
https://www.npmjs.com/package/aws-param-store
Here is my sinon code to stub the call. The function getParametersByPath is an async function
so I'm trying to return a resolved promise to stub it:
const awsParameterStore = require('aws-param-store');
const sinon = require("sinon");
let sandbox = sinon.createSandbox();
// In My Test:
let parms = new Map();
parms.set("key1","value1");
parms.set("key2","value2");
sandbox.stub(awsParameterStore,'getParametersByPath').callsFake(async function(prefix){
console.log("INSIDE STUB for getParametersByPath:" + prefix);
return Promise.resolve(parms);
});
My app makes a call to the function like this:
let parameters = await awsParameterStore.getParametersByPath("/foo");
However, instead of getting back the Map of dummy parameters, I get an empty object {}.
I can see that the stub is getting called.
Any ideas on how to properly stub this so I can return some dummy parameters in my unit tests?
Thanks!
I tried to check your code, and it's completely fine.
import test from 'ava'
const awsParameterStore = require('aws-param-store');
const sinon = require('sinon')
test('test stub', async t => {
let parms = new Map();
parms.set("key1","value1");
parms.set("key2","value2");
parms.set("key3","value3");
parms.set("key4","value4");
sinon.stub(awsParameterStore, 'getParametersByPath').callsFake(async function(prefix){
console.log("INSIDE STUB for getParametersByPath:" + prefix)
return Promise.resolve(parms);
})
const res = await awsParameterStore.getParametersByPath('/some-prefix')
console.log(JSON.stringify(res))
res.forEach((value, key) => {
console.log(`[${key}]= ${value}`)
})
t.true(true)
})
What is weir:
console.log - show that result is {}
but if you debug or log the value one by one, you can see that stub works fine:
Debugger attached.
INSIDE STUB for getParametersByPath:/some-prefix
{}
[key1]= value1
[key2]= value2
[key3]= value3
[key4]= value4
✔ test stub
UPD: problem is how to log Map by JSON.stringify(). So, you must log the map as:
console.log(JSON.stringify([...res]))
Here is the unit test solution:
index.js:
const awsParameterStore = require('aws-param-store');
async function main() {
let parameters = await awsParameterStore.getParametersByPath('/foo');
return parameters;
}
module.exports = main;
index.test.js:
const main = require('./');
const sinon = require('sinon');
const awsParameterStore = require('aws-param-store');
const { expect } = require('chai');
let sandbox = sinon.createSandbox();
describe('59787603', () => {
it('should pass', async () => {
let parms = new Map();
parms.set('key1', 'value1');
parms.set('key2', 'value2');
sandbox.stub(awsParameterStore, 'getParametersByPath').resolves(parms);
const actual = await main();
expect(actual).to.be.eql(parms);
});
});
Unit test results with 100% coverage:
59787603
✓ should pass
1 passing (11ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
index.js | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
source code: https://github.com/mrdulin/expressjs-research/tree/master/src/stackoverflow/59787603

console.log unit test failing under mocha with unknown error

My unit test failing for following code.when I run test i see below result with unknown error.I am not getting how to test second parameter paylod in console.log method.
Test console log()
-----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files | 66.67 | 100 | 0 | 66.67 | |
logger.js | 66.67 | 100 | 0 | 66.67 | 6 |
-----------|----------|----------|----------|----------|-------------------|
npm ERR! Test failed. See above for more details.
//logger.js
'use strict';
const log = (message, payload) => {
console.log(message, JSON.stringify(payload, null, 2));
};
module.exports = { log };
// log.test.js
'use strict';
const chai = require('chai');
const sinon = require('sinon');
chai.use(require('sinon-chai'));
const { expect } = chai;
const log = require('../../src/logger');
describe('Test console log()', () => {
it('should log value in console', () => {
this.stub = sinon.stub(console, 'log');
log('test invoked', { option: 1 });
});
});
Looks like you just need to destructure your require for logger.js:
'use strict';
const sinon = require('sinon');
const { log } = require('../../src/logger'); // <= destructuring assignment
describe('Test console log()', () => {
it('should log value in console', () => {
const stub = sinon.stub(console, 'log');
log('test invoked', { option: 1 });
stub.restore();
sinon.assert.calledWith(stub, 'test invoked', JSON.stringify({ option: 1 }, null, 2)); // Success!
});
});

Unit test bluebird Promise.all with Mocha/Chai

What would be the proper way to unit test this getall function using mocha/chai? I'm having a hard time understanding what to expect with Promise.all.
const Promise = require('bluebird');
const someApiService = require('./someapiservice');
const _ = require('underscore');
function getall(arr) {
let promises = _.map(arr, function(item) {
return someApiService(item.id);
});
return Promise.all(promises);
}
We should stub standalone function someApiService use link seams. This is the CommonJS version, so we will be using proxyquire to construct our seams. Additionally, I use sinon.js to create the stub for it.
E.g.
getall.js:
const Promise = require('bluebird');
const someApiService = require('./someapiservice');
const _ = require('underscore');
function getall(arr) {
let promises = _.map(arr, function (item) {
return someApiService(item.id);
});
return Promise.all(promises);
}
module.exports = getall;
someapiservice.js:
module.exports = function someApiService(id) {
return Promise.resolve('real data');
};
getall.test.js:
const proxyquire = require('proxyquire');
const sinon = require('sinon');
const { expect } = require('chai');
describe('45337461', () => {
it('should pass', async () => {
const someapiserviceStub = sinon.stub().callsFake((id) => {
return Promise.resolve(`fake data with id: ${id}`);
});
const getall = proxyquire('./getall', {
'./someapiservice': someapiserviceStub,
});
const actual = await getall([{ id: 1 }, { id: 2 }, { id: 3 }]);
expect(actual).to.deep.equal(['fake data with id: 1', 'fake data with id: 2', 'fake data with id: 3']);
sinon.assert.calledThrice(someapiserviceStub);
});
});
unit test result:
45337461
✓ should pass (2745ms)
1 passing (3s)
-------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-------------------|---------|----------|---------|---------|-------------------
All files | 88.89 | 100 | 66.67 | 88.89 |
getall.js | 100 | 100 | 100 | 100 |
someapiservice.js | 50 | 100 | 0 | 50 | 2
-------------------|---------|----------|---------|---------|-------------------

Resources