如何伪造一个直接需要的功能
How to fake a directly required function
如果我需要一个函数,我如何在 sinon 中stub/mock它?
const { getLastYearData } = require('../../services')
module.exports = async lastYearInfo => {
return getLastYearData(lastYearInfo)
}
如果我按照下面的方式操作,它可以工作,但如果不引用该对象我就无法工作。
const services = require('../../services')
module.exports = async lastYearInfo => {
return services.getLastYearData(lastYearInfo)
}
并且:
const { expect } = require('chai')
const lastYearFunction = require('./last-year-function')
const sinon = require('sinon')
const services = require('../../services')
it('should return stubbed values', async () => {
sandbox
.stub(services, 'getLastYearData')
.callsFake(lastYearInfo => {
return { Data: 4 }
})
let data = await lastYearFunction({test: 1})
const expected = {
Data: 4
}
expect(data).to.deep.equal(expected)
})
docs 显示使用 var spy = sinon.spy(myFunc);
监视任意 myFunc
。
这是节点模块工作方式引入的限制。
这一行:
const lastYearFunction = require('./last-year-function')
执行 ./last-year-function.js
中的代码,进而执行此行:
const { getLastYearData } = require('../../services')
执行 ../../services.js
中的代码,并将结果的 lastYearFunction
属性 分配给模块范围内的新变量。所有这些都发生在 sinon 准备好存根之前,因此无论如何,模块中的 getLastYearData
将引用服务返回的原始函数。
虽然可以将需要 ./last-year-function
的行移动到创建存根后的某个时间,但我不建议这样做。其一,如果需要的话,不可能恢复原来的功能。然而,更糟糕的是——require 结果被缓存在 Node 中,所以任何在同一个 运行 中需要 ./last-year-function
的东西也会使用存根。或者,会使用原始的,这取决于事物的顺序 运行。它又脏又脏,所以我不推荐它。
你最好的选择实际上是按照你对第二个样本的方式来做。通过服务对象引用它,并在 afterEach
或类似的东西中恢复它。
有 库用于代理 require
调用,这是使您的第一个代码示例工作的唯一方法。我过去用过的一个是 proxyquire。如果需要,请尝试一下,但根据我的经验,不值得增加额外的复杂性。
如果我需要一个函数,我如何在 sinon 中stub/mock它?
const { getLastYearData } = require('../../services')
module.exports = async lastYearInfo => {
return getLastYearData(lastYearInfo)
}
如果我按照下面的方式操作,它可以工作,但如果不引用该对象我就无法工作。
const services = require('../../services')
module.exports = async lastYearInfo => {
return services.getLastYearData(lastYearInfo)
}
并且:
const { expect } = require('chai')
const lastYearFunction = require('./last-year-function')
const sinon = require('sinon')
const services = require('../../services')
it('should return stubbed values', async () => {
sandbox
.stub(services, 'getLastYearData')
.callsFake(lastYearInfo => {
return { Data: 4 }
})
let data = await lastYearFunction({test: 1})
const expected = {
Data: 4
}
expect(data).to.deep.equal(expected)
})
docs 显示使用 var spy = sinon.spy(myFunc);
监视任意 myFunc
。
这是节点模块工作方式引入的限制。
这一行:
const lastYearFunction = require('./last-year-function')
执行 ./last-year-function.js
中的代码,进而执行此行:
const { getLastYearData } = require('../../services')
执行 ../../services.js
中的代码,并将结果的 lastYearFunction
属性 分配给模块范围内的新变量。所有这些都发生在 sinon 准备好存根之前,因此无论如何,模块中的 getLastYearData
将引用服务返回的原始函数。
虽然可以将需要 ./last-year-function
的行移动到创建存根后的某个时间,但我不建议这样做。其一,如果需要的话,不可能恢复原来的功能。然而,更糟糕的是——require 结果被缓存在 Node 中,所以任何在同一个 运行 中需要 ./last-year-function
的东西也会使用存根。或者,会使用原始的,这取决于事物的顺序 运行。它又脏又脏,所以我不推荐它。
你最好的选择实际上是按照你对第二个样本的方式来做。通过服务对象引用它,并在 afterEach
或类似的东西中恢复它。
有 库用于代理 require
调用,这是使您的第一个代码示例工作的唯一方法。我过去用过的一个是 proxyquire。如果需要,请尝试一下,但根据我的经验,不值得增加额外的复杂性。