Reputation: 1719
I can't figure out a way to stub a function called from within the same module this function is defined (the stub does not seem to work). Here's an example:
myModule.js:
'use strict'
function foo () {
return 'foo'
}
exports.foo = foo
function bar () {
return foo()
}
exports.bar = bar
myModule.test.js:
'use strict'
const chai = require('chai')
const sinon = require('sinon')
chai.should()
const myModule = require('./myModule')
describe('myModule', () => {
describe('bar', () => {
it('should return foo', () => {
myModule.bar().should.equal('foo') // succeeds
})
describe('when stubbed', () => {
before(() => {
sinon.stub(myModule, 'foo').returns('foo2') // this stub seems ignored
})
it('should return foo2', () => {
myModule.bar().should.equal('foo2') // fails
})
})
})
})
This reminds me of Java static functions which are not stubbable (almost).
Any idea how to achieve what I'm trying to do? I know that extracting foo
in a different module will work, but that's not what I'm trying to do here. I'm also aware that invoking foo
in the bar
method with the keyword this
will also work, I'm puzzled toward the use of ̀this
in this context (since I'm not using OOP).
Upvotes: 14
Views: 3947
Reputation: 5195
I was a bit wary of using exports
since it's a bit magical (for instance when you're coding in Typescript, you never use it directly), so I'd like to propose an alternate solution, which still requires modifying the source code unfortunately, and which is simply to wrap the function to be stubbed into an object:
export const fooWrapper = {
foo() {...}
}
function bar () {
return fooWrapper.foo()
}
And sinon.stub(fooWrapper, 'foo')
. It's a bit a shame having to wrap like that only for testing, but at least it's explicit and type safe in Typescript (contrary to to exports
which is typed any
).
Upvotes: 1
Reputation: 2309
I just tested this. And it works like charm.
'use strict'
function foo () {
return 'foo';
}
exports.foo = foo;
function bar () {
return exports.foo(); // <--- notice
}
exports.bar = bar;
Explanation
when you do sinon.stub(myModule, 'foo').returns('foo2')
then sinon
stubs the exported
object's foo
not the actually foo
function from inside your myModule.js
... as you must know, foo
is in accessible from outside the module. So when you set exports.foo
, the exported object exports.foo
stores the ref of foo
. and when you call sinon.stub(myModule, 'foo').returns('foo2')
, sinon
will stub exports.foo
and not the actual foo
Hope this makes sense!
Upvotes: 12