Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sinon - Stub module function and test it without dependency injection

I have a proxy module, which forwards function calls to services. I want to test if the service function is called, when a function in this proxy module is called.

Here is the proxy module:

const payService = require('../services/pay')
const walletService = require('../services/wallet')

const entity = {
    chargeCard: payService.payByCardToken,
    // ... some other fn
}

module.exports = entity

Based on this example and this response, I tried to stub the required module 'payService':

const expect = require('expect.js')
const sinon = require('sinon') 
const entity = require('../entity')
const payService = require('../../services/pay')

describe('Payment entity,', () => {

    it('should proxy functions to each service', () => {

        const stub = sinon.stub(payService, 'payByCardToken')
        entity.chargeCard()
        expect(payService.payByCardToken.called).to.be.ok()

    })
})

But the test fails with:

  0 passing (19ms)
  1 failing

  1) Payment entity,
       should proxy functions to each service:
     Error: expected false to be truthy
      at Assertion.assert (node_modules/expect.js/index.js:96:13)
      at Assertion.ok (node_modules/expect.js/index.js:115:10)
      at Function.ok (node_modules/expect.js/index.js:499:17)
      at Context.it (payments/test/entity.js:14:56)

And that's because payService module isn't really stubbed. I know if I add payService as a property of entity and wrap everything with a function, the test will pass:

// entity
const entity = () => {
    return {
        payService,
        chargeCard: payService.payByCardToken,
        // .. some other fn
    }
}

// test
const stub = sinon.stub(payService, 'payByCardToken')
entity().chargeCard()
expect(payService.payByCardToken.called).to.be.ok()

// test output
Payment entity,
  ✓ should proxy functions to each service

1 passing (8ms)

But that's code added only for testing puposes. Is there a way to a way to stub module functions without dependency injection and workarounds?

like image 975
AFMeirelles Avatar asked Nov 07 '17 12:11

AFMeirelles


People also ask

How do you stub a dependency of a module?

To stub a dependency (imported module) of a module under test you have to import it explicitly in your test and stub the desired method. For the stubbing to work, the stubbed method cannot be destructured, neither in the module under test nor in the test.

How do you mock a variable in Sinon?

var sinon = require('sinon'); var start_end = require('./start_end'); describe("start_end", function(){ before(function () { cb_spy = sinon. spy(); }); afterEach(function () { cb_spy. reset(); }); it("start_pool()", function(done){ // how to make timer variable < 1, so that if(timer < 1) will meet start_end.

What is the function of library Sinon?

Sinon JS is a popular JavaScript library that lets you replace complicated parts of your code that are hard to test for “placeholders,” so you can keep your unit tests fast and deterministic, as they should be.


1 Answers

The problem is that you're stubbing payService too late, after entity has already set its mappings.

If you change your test code like so:

const expect = require('expect.js')
const sinon = require('sinon') 
const payService = require('../../services/pay')

describe('Payment entity,', () => {
    let entity

    before(() => {
        sinon.stub(payService, 'payByCardToken')
        entity = require('../entity')
    })

    it('should proxy functions to each service', () => {
        entity.chargeCard()
        expect(payService.payByCardToken.called).to.be.ok()
    })
})

...you should find that entity sets itself up with your stubbed function and the assertion passes okay.

like image 154
Phil Booth Avatar answered Nov 14 '22 21:11

Phil Booth