Home  >  Q&A  >  body text

Call a stub module function in the same module

I can't find a way to stub a function called from the same module where the function is defined (stubbing doesn't seem to work). Here is 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 (almost) not stubable.

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 also know that calling foo using the keyword this in the bar method will also work, I'm not sure about using ̀this in this case Confused (because I'm not using OOP).

P粉596161915P粉596161915321 days ago645

reply all(2)I'll reply

  • P粉099000044

    P粉0990000442023-11-04 11:50:52

    I'm a bit wary of using exports since it's a bit magical (e.g. you never use it directly when coding in Typescript), so I wanted to propose an alternative solution, unfortunately The thing is that you still need to modify the source code, just wrap the function you want to stub into an object:

    export const fooWrapper = {
        foo() {...}
    }
    
    function bar () {
        return fooWrapper.foo()
    }

    and sinon.stub(fooWrapper, 'foo'). It's a bit of a shame that you have to wrap it like this just for testing, but at least it's explicit and type-safe in Typescript (as opposed to exports where the input is any). < /p>

    reply
    0
  • P粉797855790

    P粉7978557902023-11-04 00:12:56

    I just tested this. It works like a charm.

    'use strict'
    
    function foo () {
      return 'foo';
    }
    
    exports.foo = foo;
    
    function bar () {
      return exports.foo(); // <--- notice
    }
    
    exports.bar = bar;

    When you do sinon.stub(myModule, 'foo').returns('foo2'), sinon will stub the exported object's foo is not the actual foo function in myModule.js... As you must know, foo is available from outside the module access. So when you set exports.foo, the exported object exports.foo stores the ref of foo. When you call sinon.stub(myModule, 'foo').returns('foo2'), sinon will stub exports.foo which is not the actual foo

    Hope this makes sense!

    reply
    0
  • Cancelreply