Sinon - 桩模块函数并在不依赖注入的情况下进行测试

7
我有一个代理模块,它将函数调用转发到服务。我想测试当调用该代理模块中的函数时,服务函数是否被调用。
以下是代理模块:
const payService = require('../services/pay')
const walletService = require('../services/wallet')

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

module.exports = entity

基于此示例此回答,我尝试去存根所需的模块 '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()

    })
})

但是测试失败了,显示:
  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)

这是因为 payService 模块并没有真正被存根化。我知道如果将 payService 添加为实体的属性并用一个函数包装所有内容,测试就会通过:
// 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)

但那只是为了测试目的而添加的代码。有没有一种方法可以在不使用依赖注入和变通方法的情况下存根模块函数?
1个回答

9
问题在于您太晚才对payService进行桩数据操作,在此之前,entity已经设置了其映射关系。
如果您按照以下方式更改测试代码:
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()
    })
})

如果你按照上面的方式操作,你会发现entity已经使用你的存根函数并且断言已经通过了。


如果payService是一个模块(具有一堆例程,而不是类,其测试实例在测试结束时消失...),请记得使用.restore()来删除存根,以避免对下一个测试产生副作用... - Frank N
这个主题在哪里可以阅读更多相关内容? 为什么初始代码不起作用? 在运行时进行所需操作是一个好主意吗? - user1398619

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接