Testing for method calls using sinon on module.exports methods - javascript

I'm trying to test if a specific method is called given certain conditions using mocha, chai and sinon. Here is the code:
function foo(in, opt) {
if(opt) { bar(); }
else { foobar(); }
}
function bar() {...}
function foobar() {...}
module.exports = {
foo: foo,
bar: bar,
foobar:foobar
};
Here is the code in my test file:
var x = require('./foo'),
sinon = require('sinon'),
chai = require('chai'),
expect = chai.expect,
should = chai.should(),
assert = require('assert');
describe('test 1', function () {
it('should call bar', function () {
var spy = sinon. spy(x.bar);
x.foo('bla', true);
spy.called.should.be.true;
});
});
When I do a console.log on the spy it says it wasn't called even thou with manual logging in the bar method I'm able to see it gets called. Any suggestions on what I might be doing wrong or how to go about it?
Thanks

You've created a spy, but the test code doesn't use it. Replace the original x.bar with your spy (don't forget to do cleanup!)
describe('test 1', function () {
before(() => {
let spy = sinon.spy(x.bar);
x.originalBar = x.bar; // save the original so that we can restore it later.
x.bar = spy; // this is where the magic happens!
});
it('should call bar', function () {
x.foo('bla', true);
x.bar.called.should.be.true; // x.bar is the spy!
});
after(() => {
x.bar = x.originalBar; // clean up!
});
});

Related

How to stub IIFE module

I am running Node v16.11.0. Trying to test a Worker module that I defined as such:
const Worker = (function(){
function start(){...}
function stop(){...}
function privateFunction1(){
...some stuff
...calls privateFunction2();
}
function privateFunction2(){...}
return {
start: start,
stop: stop,
/** for testing only:**/
_privateFunction1: privateFunction1,
_privateFunction2: privateFunction2
}
})();
module.exports = Worker;
And in my test file I have:
const worker = require("../../worker");
const sinon = require("sinon");
const chai = require("chai");
var assert = chai.assert;
var expect = chai.expect;
describe("Worker", function () {
const sandbox = sinon.createSandbox();
describe("#privateFunction1", function () {
.....
beforeEach(function () {
removeStub = sandbox.stub(worker, "_privateFunction2");
.......
});
afterEach(function () {
sandbox.restore();
});
it("should test something", function () {
let obj = {} //just for demo purposes
assert.equal(worker._privateFunction1(obj), false);
});
The expectation here is that _privateFunction1() will start executing, will call the privateFunction2 and that call will be handled by the stub.
But the real method gets called instead. Stubbing doesn't work.
Anyone has any ideas what is missing here?
Thanks

Stub internal calls on dependency of library with Sinon.js

I am writing a library which has an entry file that looks like this:
function MyLibrary(options){
this._options = {// defaults here};
this.setupOptions(options);
this._initInstance();
}
MyLibrary.prototype.randomMethod = function(){
}
MyLibrary.prototype._initInstance = function(){
this._loadImage();
this._internalInstance = new OtherThirdPartyDependency(this._options);
}
module.exports = MyLibrary;
In my tests, I would like to create a real instance of MyLibrary, but I want to create a stub of OtherThirdPartyDependency.
Here is my test file so far. How can I achieve this?
describe('My Library Module', () => {
let sandbox;
let myLibInstance;
beforeEach(() => {
sandbox = sinon.createSandbox({});
myLibInstance = new MyLibrary({option: 1, option: 2});
// FAILS HERE because initializing MyLibrary make a call OtherThirdPartyDependency constructor.
});
afterEach(() => {
sandbox.restore();
});
it('should call setOptions and _loadImage on init', () => {
expect(myLibInstance.setOptions).to.have.been.calledOnce;
expect(myLibInstance._loadImage).to.have.been.calledOnce;
})
});
There is a method in sinon createStubInstance, but I'm not sure how to apply in here because OtherThirdPartyDependency is not a method that I can directly stub on MyLibrary. How can I stub OtherThirdPartyDependency?

How to overwrite (or mock) a class method with Jest in order to test a function?

I have an issue with a unit test of a function which calls a class. It seems that it always calls the "official" class instance and not my mocked class. I'm not able to force my function to use my mocked instance...
There is a file with the function I want to test:
const myClass = require('./myClass');
const instance = new myClass();
module.exports.functionToTest = async function () {
// Some stuff...
const value = await instance.myMethod();
// Some stuff that define a result variable (partially with value).
return result;
}
There is a file with my class definition:
module.exports = class myClass {
async myMethod() {
const result = await someStuffWillResolveMaybeTrueOrFalse();
console.log('We used the original myMethod... Mocking has failed.');
return result;
}
}
There is a spec file:
const myFile = require('./myFile');
const myClass = require('./myClass');
describe('My test', async () => {
it('should mock myClass.myMethod in order to return false', () => {
const instance = new myClass();
instance.myMethod = jest.fn().mockResolvedValue(false);
const result = await myFile.functionToTest();
expect(result).toBeTruthy();
}
}
Unfortunately my test is passing (because myMethod return "true") and log "We used the original myMethod... Mocking has failed."
So I want to make my test always fail by mocking that myMethod to return false.
Can you help me? Thanks for your time.
Hm. I've found a solution.
See. A change in my file with the target function.
const myClass = require('./myClass');
// const instance = new myClass(); <== Not here...
module.exports.functionToTest = async function () {
const instance = new myClass(); // <== ...but there.
// Some stuff...
const value = await instance.myMethod();
// Some stuff that define a result variable (partially with value).
return result;
}
And my spec file :
const myFile = require('./myFile');
// I specify to Jest that I'll mock a file
jest.mock('./myClass');
const myClass = require('./myClass');
// I prepare the mock function. In that case a promise wich resolve 'false'
const mMock = jest.fn().mockResolvedValue(false);
// I mock the method 'myMethod' in 'myClass'
myClass.mockImplementation(() => {
return {
myMethod: mMock
};
});
// Then, I just take the test
describe('My test', async () => {
it('should mock myClass.myMethod in order to return false', () => {
const result = await myFile.functionToTest();
expect(result).toBeFalsy();
}
}

sinon stub not replacing function

I'm trying to use sinon stub to replace a function that might take along time. But when I run the tests, the test code doesn't seem to be using the sinon stubs.
Here is the code I'm trying to test.
function takeTooLong() {
return returnSomething();
}
function returnSomething() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('ok')
}, 1500)
})
}
module.exports = {
takeTooLong,
returnSomething
}
and this is the test code.
const chai = require('chai')
chai.use(require('chai-string'))
chai.use(require('chai-as-promised'))
const expect = chai.expect
chai.should()
const db = require('./database')
const sinon = require('sinon')
require('sinon-as-promised')
describe('Mock the DB connection', function () {
it('should use stubs for db connection for takeTooLong', function (done) {
const stubbed = sinon.stub(db, 'returnSomething').returns(new Promise((res) => res('kk')));
const result = db.takeTooLong()
result.then((res) => {
expect(res).to.equal('kk')
sinon.assert.calledOnce(stubbed);
stubbed.restore()
done()
}).catch((err) => done(err))
})
I get an assertion error
AssertionError: expected 'ok' to equal 'kk'
+ expected - actual
-ok
+kk
What am I doing wrong? Why isn't the stub being used ? The test framework in Mocha.
Sinon stubs the property of the object, not the function itself.
In your case you are exporting that function within an object.
module.exports = {
takeTooLong,
returnSomething
}
So in order to properly call the function from the object, you need to replace your function call with the reference to the export object like :
function takeTooLong() {
return module.exports.returnSomething();
}
Of course based on your code, you can always refactor it :
var exports = module.exports = {
takeTooLong: function() { return exports.returnSomething() }
returnSomething: function() { /* .. */ }
}
You might want to have a look at Proxyquire to stub/spy directly exported functions.
https://www.npmjs.com/package/proxyquire/

Any equivalent to Mockito's ArgumentCaptor in javascript test framework?

I would like to capture the parameter passed to a stub method. And then I can perform assertion on the properties of that parameter. For Java, it is Mockito's ArgumentCaptor. Is there any equivalent thing in javascript test framework?
Here's an example:
const assert = require('chai').assert;
const expect = require('chai').expect;
const sinon = require('sinon');
const obj = {
divideByFive(a) {
return a / 5;
},
testFunc(a, b) {
return this.divideByFive(a + b) + 23;
}
};
describe('obj.testFunc()', () => {
afterEach(() => {
// Restore to the original implementation
obj.divideByFive.restore();
});
it('should call divideByFive() with the right arguments', () => {
var spy = sinon.spy(obj, 'divideByFive');
obj.testFunc(42, 1337);
assert(spy.calledWith(1379));
});
it('should return the value returned by divideByFive(), increased by 23', () => {
sinon.stub(obj, 'divideByFive').returns(1234);
expect(obj.testFunc(42, 1337)).to.equal(1257);
});
});
You can use .calledWith() (provided by Sinon) to check if a spy/stub was called with particular arguments. You should consult the documentation for more options.
Here's a standalone Mocha test to check if a spy got called with an object that had particular properties set to particular values:
const assert = require('chai').assert;
const sinon = require('sinon');
const spy = sinon.spy();
// Call the spy with an object argument.
spy({ foo : 'bar', xxx : 'yyy' });
// Check the properties.
it('should have called spy with foo:bar', function() {
assert( spy.calledWithMatch({ foo : 'bar' }) );
});
it('should have called spy with xxx:yyy', function() {
assert( spy.calledWithMatch({ xxx : 'yyy' }) );
});
it('should have called spy with xxx:zzz (WILL FAIL)', function() {
assert( spy.calledWithMatch({ xxx : 'zzz' }) );
});

Categories