I want to stub a internal function in my code when unit testing it, example:
//foobar.js
const uuid = require('uuid');
function foo() {
console.log('uuid: ' + uuid.v4());
// Lots of timers
}
exports._foo = foo;
function bar() {
//Logic...
foo();
//Logic...
}
exports.bar = bar;
And the unit test:
// test/foobar.js
const chai = require('chai'),
expect = chai.expect,
proxyquire = require('proxyquire'),
sinon = require('sinon');
describe('bar', () => {
it('call foo', () => {
let foo = proxyquire('./foo.js', {
uuid: {
v4: () => {
return '123456789';
}
}
}),
fooSpy = sinon.spy(foo._foo);
foo.bar();
expect(fooSpy.calledOnce);
});
});
Now, when unit testing bar, I can spy on foo just fine, and it is quite fine.
However, the real foo make a lot of time consuming calls (DB calls, file IO...), and while I could use proxyquire to stub all fs and db calls to terminate immediately, that would duplicate code from the test of foo, be unreadable, and being bad altogether.
The simple solution would be to stub foo, but proxyquire doesn't seems to like that. A naive foo._foo = stubFoo didn't worked either. Rewire doesn't seems to handle this either.
What I could do would be to make a file that import and export foobar.js, and use proxyquire on it, but the idea itself is already bad.
How can I stub the foo function when testing bar?
Sinon is perfectly capable to handle this if done correctly, you just need to remember sinon replace references in the object, and export is not where the function is declared. But with the same code and tests, a simple modification to bar make it works:
function bar() {
//Logic...
exports._foo();
//Logic...
}
Related
I have some code that goes like this:
function foo() {
return 'bar';
}
function bar() {
return 'foo';
}
var hello = 'world';
var world = 'hello';
I want to use these functions and variables in a different file. I know I can use module.exports = {foo, bar, hello, world} and then require const foofile = require('./foofile.js')in a different file, but that makes me use them like foofile.foo(). Is there and way I can avoid this so I just have to type foo() in the other file?
Edit:
I see the 2 answers but when I test the code everything I require is undefined. I might as well just put it here, since it isn't that long anyway.
// vars.js (in root folder)
const sleep = require('./functions/sleep');
const scenarios = require('./scenarios.json')
const fs = require('fs');
const Discord = require('discord.js')
const client = new Discord.Client();
module.exports = {sleep, scenarios, fs, Discord, client}
// sleep.js (in subfolder functions)
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
module.exports = sleep;
//startTheGame.js (in subfolder functions)
const {sleep, scenarios, fs, Discord, client} = require('../vars')
async function startTheGame(channel) {
await sleep(1500);
const embed = Discord.MessageEmbed();
}
module.exports = startTheGame;
It's returning sleep is not a function and when I delete await sleep(1500); it returns cannot read property MessageEmbed of undefined.
I know this is becoming pretty long, and it might be because of a simple slip-up by me, but if anyone could help me, that would be great. Hope this helps someone else.
You can import them using object destructuring like this:
const {foo, bar, hello, world} = require('./foofile.js');
Then, foo, bar, hello and world will be top level variables in your module and you can just refer to them directly as in foo().
You can destruct the content required from the module, therefore you can avoid the mentioned syntax of foofile.foo().
Consider the module you described and a index.js which is requiring it using the destructuring syntax.
// mymodule.js
function foo() {
return "bar";
}
function bar() {
return "foo";
}
// Consider using const and let instead of var
const hello = "world";
const world = "hello";
module.exports = { foo, bar, hello, world };
// index.js
const { foo, bar, hello, world } = require('./mymodule');
console.log(foo()); // "bar"
console.log(bar()); // "foo"
console.log(hello); // "world"
console.log(world); // "hello"
let's say i have a function
Func a() {
//Do Something
let c = b();
return c;
}
I want to test the function a and mock b() and in the mock want to assign c.
Sinon.Stub(Test,"b").returns("DummyValue");
c should be assigned DummyValue.
How can I do that?
describe("a", () => {
let a = a();
//mock b();
action = execute(a);
expect(action).should.return.("DummyValue");
})
When we have 2 functions in the same file and want to stub one of them and test the other.
For example,:
Test: tests.js
let ComputeSumStub = sinon.stub(OfflineLoader, "ComputeSum");
const ans = function ()
{
return 10;
};
ComputeSumStub.returns(ans);
const actualValue: number = OfflineLoader.sum();
expect(actualValue).to.be.equal(10);
Dev: foo.js
function sum(): number
{
return ComputeSum(8, 9);
}
function ComputeSum(a: number, b: number): number
{
return a + b;
}
We cannot do that, because after compilation the functions are exported with different signatures, with full name and while stubbing we stub the global function but while calling it from within the other function, we call the local function, hence it doesn’t work.
There is a workaround to do that.
foo.js
const factory = {
a,
b,
}
function a() {
return 2;
}
function b() {
return factory.a();
}
module.exports = factory;
test.js
const ser = require('./foo');
const sinon = require('sinon');
const aStub = sinon.stub(ser, 'a').returns('mocked return');
console.log(ser.b());
console.log(aStub.callCount);
Ref: Stubbing method in same file using Sinon
You can stub function only
if you pass it as parameter ans fake it with test doubles library like sinon
or if it is dependency (loaded via import or require). In such case you can use proxyquire to pass in your fake b function for module under test. Function itself can be faked by sinon or other test doubles library.
In this case a sinon stub is more appropriate then a mock
When to use mocks vs stubs?
The rule of thumb is: if you wouldn’t add an assertion for some
specific call, don’t mock it. Use a stub instead.
Our assertion in the test is not on a specific call of function a i.e 1st or 3rd call but on all calls.
We can tel this because we have programmed our stub to always return the same result regardless of the way in which it is being called (arguments, or number of calls).
Pass a sinon stub function as an argument to function a.
Function a(b) {
const c = b();
return c;
}
test.js
require("sinon")
describe("a", () => {
const stub = sinon.stub();
stub.returns("DummyValue");
expect(a(stub)).to.eql.("DummyValue");
})
Note that we can use const for these variable declarations as they are never being reassigned.
I'm trying to unit test a function in a file while stubbing another function in the SAME file, but the mock is not being applied and the real method is being called. Here's an example:
// file: 'foo.js'
export function a() {
// .....
}
export function b() {
let stuff = a(); // call a
// ...do stuff
}
And my test:
import * as actions from 'foo';
const aStub = sinon.stub(actions, 'a').returns('mocked return');
actions.b(); // b() is executed, which calls a() instead of the expected aStub()
Some restructuring can make this work.
I've used commonJS syntax. Should work in the same way in ES6 as well.
foo.js
const factory = {
a,
b,
}
function a() {
return 2;
}
function b() {
return factory.a();
}
module.exports = factory;
test.js
const ser = require('./foo');
const sinon = require('sinon');
const aStub = sinon.stub(ser, 'a').returns('mocked return');
console.log(ser.b());
console.log(aStub.callCount);
Output
mocked return
1
While the above does work, it's definitely a workaround as my linter was quick to inform.
I ended up separating modules and using proxyquire. This library allows you to easily substitute any / all exports with those of your choosing, sinon stub spy or mocks included. e.g. :
in b.js
export const fnB = () => 'hey there!';
in a.js
import { fbB } from 'b.js';
export const fnA = () => fbB();
in a.test.js
import { noCallThru } from 'proxyquire';
const proxyquireStrict = noCallThru();
const stubB = stub().returns('forced result');
const moduleA = proxyquireStrict('a.js', {
'b.js' : { fnB: stubB }
}).fnA;
console.log(fnA()); // 'forced result'
The method mentioned above (using a factory to collect the functions) works well; however, eslint will not like the use of a variable/function that has not yet been declared. Therefore I would recommend a slight modification:
// my-functions.js
export const factory = {};
export const funcA = () => {
return facory.funcB();
};
factory.funcA = funcA;
export const funcB = () => true;
factory.funcB = funcB;
// my-functions-test.js
import {factory, funcA, funcB} from './path/to/my-functions';
describe('MyFunctions | funcA', () => {
test('returns result from funcB call', () => {
const funcBStub = sinon.stub(factory, 'funcB').returns(false);
// Test that the function does not throw errors
let result;
expect(() => (result = funcA())).not.toThrow();
// Test that the return value is that of the mock rather than the original function
expect(result).toEqual(false);
// Test that the stub was called
expect(funcBStub.called).toEqual(true);
});
});
// Don't forget to test funcB independently ;)
The important distinction is to add the functions within the file to the factory as they are defined to avoid break eslint rules. The only case where this could cause issues is if you tried calling one of those functions within the same file before they have all been defined. Example:
// my-functions-1.js
export const factory = {};
export const funcA = () => {
factory.funcB();
};
factory.funcA = funcA;
// Since the code execution runs from top to bottom, calling funcA here means that funcB has not yet been added to factory
funcA(); // Throws an error since factory.funcB() is not a function (yet)
export const funcB = () => true;
factory.funcB = funcB;
I prefer this technique of using a "collector" to call functions within the same file since it is not always a great idea to create separate files for EACH function that you write. Often, I find that I will create many related utility functions in order to make my code more readable, reusable, and composable; putting each function into a separate file would make the code slightly more difficult to understand since a reader could not see the definitions of these functions without bouncing between different files.
I met with the same issue and found one method. You can change your foo.js file to this:
// file: 'foo.js'
export function a() {
// .....
}
export function b() {
let stuff = exports.a(); // using "exports." to call a
// ...do stuff
}
Please refer to https://codeburst.io/stub-dependencies-with-sinon-js-259ac12379b9.
I put the following code in its own file called shared.js
afterEach(function () {
// insert code
});
var foo;
beforeEach(function () {
foo = {
bar: []
};
});
exports = module.exports = {};
exports.foo = foo;
I'd like the afterEach and beforeEach to be ran in every mocha.js test I have. so in each test file, I required shared.js.
The problem is it seems foo isn't available in the scope of my tests. foo.bar is undefined and inaccessible. The beforeEach() and afterEach hooks are running just fine, but I'm having trouble understanding how to properly export the scope of foo. This might be more of a Node.js problem than an actual Mocha problem.
The problem is that you can not modify the exported reference. In your case you are exporting undefined, because foo is uninitialized. If you initialize foo with an empty object and later try to reassign it to a different thing/object it will still not work because the exported reference is still the same.
The only thing you can do is modifying (mutating) the exported object like so:
afterEach(function () {
// insert code
});
var foo = {};
beforeEach(function () {
foo.bar = [];
});
exports = module.exports = {};
exports.foo = foo;
If you want something that is specific to the context of each test, you can do something like the following:
afterEach(function () {
// insert code
});
beforeEach(function () {
this.foo = [];
});
exports = module.exports = {};
each test can then access its own this.foo:
describe('myTest', function() {
it('should do something', function() {
this.foo.push("1"); // same 'this' as from beforeEach
// ...insert code
})
})
Please don't suggest to use Sinon. I want to get chai-spies specifically chai.spy.on working with your help. Basically, I have this spec. Inside my initialize method in PatientController, I call this.initializePatientEvents();
beforeEach(function() {
this.patientController = new PatientController({model: new Backbone.Model(PatientModel)});
});
it('executes this.initializePatientEvents', function () {
let spy = chai.spy.on(this.patientController, 'initializePatientEvents');
expect(spy).to.have.been.called();
});
However, the test is failing with this error
AssertionError: expected { Spy } to have been called
at Context.<anonymous>
I spent almost 3 hours now with no luck! :(
Moving my comment above to a response here:
Looking at your code, I'm just not sure what the this reference refers to. And based on your error message, it seems like its related to something about the context. Therefore, I'd try something like this:
var patientController;
beforeEach(function() {
patientController = new PatientController({model: new Backbone.Model(PatientModel)});
});
it('executes this.initializePatientEvents', function () {
let spy = chai.spy.on(patientController, 'initializePatientEvents');
expect(spy).to.have.been.called();
});
If this doesn't work, then its more specific to your implementation of patientController and the initializePatientEvents method, and not something related to chai.spy.
EDIT:
Here's something I set up locally and I was able to get a passing test. The main difference is that instead of using Backbone, I just created my own constructor function.
"use strict";
var chai = require("chai");
var sinon = require("sinon");
var sinonChai = require("sinon-chai");
chai.use(sinonChai);
var expect = chai.expect;
var should = chai.should();
describe("PatientController Test", function() {
var PatientController;
var initializePatientEventsSpy;
var patient;
beforeEach(function() {
PatientController = function(name, age) {
this.name = name;
this.age = age;
this.initializePatientEvents();
};
PatientController.prototype.initializePatientEvents = function() {
console.log("Do some initialization stuff here");
};
initializePatientEventsSpy = sinon.spy(PatientController.prototype, "initializePatientEvents");
});
it("should test initializePatientEvents was called", function() {
patient = new PatientController("Willson", 30);
initializePatientEventsSpy.should.have.been.called;
});
});
If the PatientController constructor is what calls initializePatientEvents, then the timing of your spy creation is a bit off. Currently, the order of your spy-function relationship is:
Call function
Spy on function
Expect spied on function to have ben called
Because the function is not being spied on when it is called, the spy misses the call entirely. What the order should be is:
Spy on function
Call function
Expect spied on function to have ben called
However, you are in the sticky situation where the object you are spying on doesn't exist until after the constructor is called. One workaround would be to assert that the effects of the initializePatientEvents have taken place instead of asserting that the function was called.