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.
Related
A beforeFilter is that block of code which is executed before calling any function. I am new to javascript.
Lets say I have a module:
SomeModule.js
module.exports = {
someFunction: function (arg) {
//some logic here
},
}
Now whenever I want to call the above function, I will do:
SomeModule.someFunction("helloWorld");
Like this you can assume I got many functions in the module but I want to execute some code before calling any function of the module, lets say I want to execute this line:
console.log("BeforeFilter Called");
So question is:
How can I ensure that the line gets executed before calling any function of the module ?
You have to iterate over properties of SomeModule and overwrite all properties which are functions:
const SomeModule = {
someFunction(a, b) {
console.log('some function', a + b);
}
};
for (const i in SomeModule) {
if (typeof SomeModule[i] === 'function') {
const originalFunction = SomeModule[i];
SomeModule[i] = function (...args) {
console.log('BeforeFilter Called');
originalFunction(...args);
};
}
}
SomeModule.someFunction(3, 4);
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...
}
This question already has answers here:
In Node.js, how do I "include" functions from my other files?
(28 answers)
Closed 5 years ago.
Suppose I have a module, named mainModule.js, that has the statement.
var helper_formatModule = require('/formatModule.js');
Inside formatModule.js, I also have a statement,
var helper_handleSentences = require('/handleSentences.js');
If my original module, mainModule.js, needs functions defined in the handleSentences.js module would it be able to access them? I.e if it imported formatModule, a module that has handleSentences, does it have access to those? Or would I need to import the handleSentences.js module directly?
Only requiring a module A somewhere (in module B, for example) doesn't make the functions of A accessible in other modules. Normally, they're not even accessible in module B.
To access functions (or any values) from another module, that other module has to export them. The following scenario will not work:
// module-a.js
function firstFunction () {}
function secondFunction () {}
// module-b.js
var helper_handleSentences = require('/handleSentences.js');
// do something with 'helper_handleSentences'
module.exports = function (a) {
return helper_handleSentences(a);
}
As you can see, module-a.js doesn't export anything. Thus, the variable a holds the default export value, which is an empty object.
In your situation, you can either
1. require both modules in mainModule.js
// handleSentences.js
function doSomethingSecret () {
// this function can only be accessed in 'handleSentences.js'
}
function handleSentences () {
// this function can be accessed in any module that requires this module
doSomethingSecret();
}
module.exports = handleSentences;
// formatModule.js
var helper_handleSentences = require('/handleSentences.js');
// do something with 'helper_handleSentences'
module.exports = function (a) {
return helper_handleSentences(a);
};
// mainModule.js
var helper_handleSentences = require('/handleSentences.js');
var helper_formatModule = require('/formatModule.js');
// do something with 'helper_handleSentences' and 'helper_formatModule'
2. merge the exported values of both modules into one object
// handleSentences.js
function doSomethingSecret () {
// this function can only be accessed in 'handleSentences.js'
}
function handleSentences () {
// this function can be accessed in any module that requires this module
doSomethingSecret();
}
module.exports = handleSentences;
// formatModule.js
var helper_handleSentences = require('/handleSentences.js');
// do something with 'helper_handleSentences'
function formatModule (a) {
return helper_handleSentences(a);
};
module.exports = {
handleSentences: helper_handleSentences,
format: formatModule
};
// mainModule.js
var helper_formatModule = require('/formatModule.js');
// use both functions as methods
helper_formatModule.handleSentences();
helper_formatModule.format('...');
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.
Say I have a module with two functions with one depending on the other:
// example.js
function A() {
return "hello";
}
function B() {
return A();
}
module.exports.B = B;
Can I use rewire to mock the call to A() in B()?
// example.test.js
var assert = require('chai').assert,
rewire = require('rewire'),
example = rewire('./example.js');
example.__set__({
A: function( return 'goodbye';),
});
describe('test B in example.js', function() {
it('should return "goodbye"', function() {
assert.strictEqual(example.B(), 'goodbye');
});
});
Yes, this does work. I'm not sure what solved the problem exactly. Previously I was exporting the dependent function as part of a function prototype (e.g. function.prototype.dependentFunction = function() { };) and somehow this was messing with rewire. I redefined my function by declaring/defining it first and then attaching it to the model:
function dependentFunction() { ... }
exportedObject.prototype.dependentFunction = dependentFunction();
Doing this fixed my problems.