用 sinon 存根 express 中间件函数是
Stubbing express middleware functions with sinon is
描述
我尝试为 express 中间件函数设置存根伪造,但它没有被替换。
我在尝试什么(如何重现)
我正在尝试通过 callsFake
函数使用 sinon stubbing,正如他们最新文档中所建议的那样。
即使我需要模块并在导出时替换 属性 中的函数。我不断看到原始函数行为在起作用。
我知道我应该尝试在设置中间件函数之前将函数存根,那是第一次导入 express app
的时候。
这是我要存根的函数,定义为函数并导出为对象。它在脚本文件中定义,路径类似于 api/middlewares/stripe/signature
.
const stripeHelper = require('../../../lib/stripe')
const logger = require('../../../lib/logger')
const verifySignature = (req, res, next) => {
var event
let eventName = req.url.replace('/', '')
try {
// Try adding the Event as `request.event`
event = stripeHelper.signatureCheck(
eventName,
req.body,
req.headers['stripe-signature']
)
} catch (e) {
// If `constructEvent` throws an error, respond with the message and return.
logger.error('Error while verifying webhook request signature', e.message, e)
return res.status(400).send('Webhook Error:' + e.message)
}
req.event = event
next()
}
module.exports.verifySignature = verifySignature
我已经试过了
- 使用 decache 确保 express 应用程序实例是原始的,并且没有使用以前的原始中间件进行初始化
- 设置多个
beforEach
挂钩以组织我的存根和先决条件或测试
不断发生的事情
- 原中间件功能得到执行
- 我没有看到存根函数的任何日志(作为 sinon 存根不起作用的第二个证据
这是我的存根和测试挂钩设置:
const chai = require('chai')
const chaiHttp = require('chai-http')
const dirtyChai = require('dirty-chai')
const sinon = require('sinon')
const decache = require('decache')
const signatureMiddleware = require('../../../api/middlewares/stripe/signature')
const bp = require('body-parser')
let verifySignatureStub, rawStub
chai.should()
chai.use(dirtyChai)
chai.use(chaiHttp)
const API_BASE = '/api/subscriptions'
const planId = 'NYA-RUST-MONTHLY'
const utils = require('../../utils')
const {
hooks: {createSubscription, emitPaymentSucceeded},
stripe: {generateEventFromMock}
} = utils
let testUser, testToken, testSubscription, server
describe.only('Subscriptions renewal (invoice.payment_succeeded)', function () {
this.timeout(30000)
beforeEach(function (done) {
createSubscription(server, {planId}, function (err, resp) {
if (err) return done(err)
const {user, jwt, subscription} = resp
console.log(user, jwt)
testUser = user
testToken = jwt
testSubscription = subscription
done()
})
})
beforeEach(function (done) {
verifySignatureStub = sinon.stub(signatureMiddleware, 'verifySignature')
rawStub = sinon.stub(bp, 'raw')
rawStub.callsFake(function (req, res, next) {
console.log('bp raw')
return next()
})
verifySignatureStub.callsFake(function (req, res, next) {
const {customerId} = testUser.stripe
const subscriptionId = testSubscription.id
console.log('fake verify')
req.event = generateEventFromMock('invoice.payment_failed', {subscriptionId, customerId, planId})
return next()
})
done()
})
beforeEach(function (done) {
decache('../../../index')
server = require('../../../index')
const {customerId} = testUser.stripe
const {id: subscriptionId} = testSubscription
console.log(`emitting payment succeeded with ${customerId}, ${subscriptionId} ${planId}`)
emitPaymentSucceeded(server, testToken, function (err, response) {
if (err) return done(err)
done()
})
})
afterEach(function (done) {
verifySignatureStub.restore()
done()
})
it('Date subscription will renew gets set to a valid number roughly one month', function () {
// Not even getting here becasue calling the original function contains verifyMiddleware which should be replaced
})
it('Current period end is modified')
it('An invoice for the new starting period is generated')
it('Subscription status keeps active')
})
上下文(请填写以下信息):
全部运行在节点 8 上,我正在 运行 使用 mocha 进行测试并使用 dirty chai 进行设置。
这些是我的开发依赖项:
"devDependencies": {
"base64url": "^2.0.0",
"cross-env": "^5.0.5",
"decache": "^4.4.0",
"dirty-chai": "^2.0.1",
"faker": "^4.1.0",
"google-auth-library": "^0.12.0",
"googleapis": "^23.0.0",
"minimist": "^1.2.0",
"mocha": "^5.2.0",
"nodemon": "^1.12.0",
"nyc": "^11.2.1",
"sinon": "^6.1.5",
"standard": "^10.0.3",
"stripe-local": "^0.1.1"
}
未决问题
根据经验,应该在每个测试中设置存根,即在 beforeEach
或 it
中,而不是在 before
中。在这里,它们似乎不包含每个测试逻辑,但它们可以,在这种情况下,它们将无法按预期使用 before
。 mocha-sinon
最好用于将 Mocha 与 Sinon 沙箱集成,因此不需要 afterEach
来恢复存根,这是自动完成的。
由于 verifySignature
是导出 属性 而不是导出本身,因此 signatureMiddleware
模块可能会保留原样,但使用它的模块应该被取消缓存并重新导入在他们预期使用 verifySignature
的测试中。如果整个测试套件的行为应该相同,那么也应该在 beforeEach
中执行。例如。如果直接在app
模块中使用这些中间件,则为:
const decache = require('decache');
...
describe(() => {
let app;
beforeEach(() => {
verifySignatureStub = sinon.stub(signatureMiddleware, 'verifySignature');
...
});
beforeEach(() => {
decache('./app');
app = require('./app');
});
描述
我尝试为 express 中间件函数设置存根伪造,但它没有被替换。
我在尝试什么(如何重现)
我正在尝试通过 callsFake
函数使用 sinon stubbing,正如他们最新文档中所建议的那样。
即使我需要模块并在导出时替换 属性 中的函数。我不断看到原始函数行为在起作用。
我知道我应该尝试在设置中间件函数之前将函数存根,那是第一次导入 express app
的时候。
这是我要存根的函数,定义为函数并导出为对象。它在脚本文件中定义,路径类似于 api/middlewares/stripe/signature
.
const stripeHelper = require('../../../lib/stripe')
const logger = require('../../../lib/logger')
const verifySignature = (req, res, next) => {
var event
let eventName = req.url.replace('/', '')
try {
// Try adding the Event as `request.event`
event = stripeHelper.signatureCheck(
eventName,
req.body,
req.headers['stripe-signature']
)
} catch (e) {
// If `constructEvent` throws an error, respond with the message and return.
logger.error('Error while verifying webhook request signature', e.message, e)
return res.status(400).send('Webhook Error:' + e.message)
}
req.event = event
next()
}
module.exports.verifySignature = verifySignature
我已经试过了
- 使用 decache 确保 express 应用程序实例是原始的,并且没有使用以前的原始中间件进行初始化
- 设置多个
beforEach
挂钩以组织我的存根和先决条件或测试
不断发生的事情
- 原中间件功能得到执行
- 我没有看到存根函数的任何日志(作为 sinon 存根不起作用的第二个证据
这是我的存根和测试挂钩设置:
const chai = require('chai')
const chaiHttp = require('chai-http')
const dirtyChai = require('dirty-chai')
const sinon = require('sinon')
const decache = require('decache')
const signatureMiddleware = require('../../../api/middlewares/stripe/signature')
const bp = require('body-parser')
let verifySignatureStub, rawStub
chai.should()
chai.use(dirtyChai)
chai.use(chaiHttp)
const API_BASE = '/api/subscriptions'
const planId = 'NYA-RUST-MONTHLY'
const utils = require('../../utils')
const {
hooks: {createSubscription, emitPaymentSucceeded},
stripe: {generateEventFromMock}
} = utils
let testUser, testToken, testSubscription, server
describe.only('Subscriptions renewal (invoice.payment_succeeded)', function () {
this.timeout(30000)
beforeEach(function (done) {
createSubscription(server, {planId}, function (err, resp) {
if (err) return done(err)
const {user, jwt, subscription} = resp
console.log(user, jwt)
testUser = user
testToken = jwt
testSubscription = subscription
done()
})
})
beforeEach(function (done) {
verifySignatureStub = sinon.stub(signatureMiddleware, 'verifySignature')
rawStub = sinon.stub(bp, 'raw')
rawStub.callsFake(function (req, res, next) {
console.log('bp raw')
return next()
})
verifySignatureStub.callsFake(function (req, res, next) {
const {customerId} = testUser.stripe
const subscriptionId = testSubscription.id
console.log('fake verify')
req.event = generateEventFromMock('invoice.payment_failed', {subscriptionId, customerId, planId})
return next()
})
done()
})
beforeEach(function (done) {
decache('../../../index')
server = require('../../../index')
const {customerId} = testUser.stripe
const {id: subscriptionId} = testSubscription
console.log(`emitting payment succeeded with ${customerId}, ${subscriptionId} ${planId}`)
emitPaymentSucceeded(server, testToken, function (err, response) {
if (err) return done(err)
done()
})
})
afterEach(function (done) {
verifySignatureStub.restore()
done()
})
it('Date subscription will renew gets set to a valid number roughly one month', function () {
// Not even getting here becasue calling the original function contains verifyMiddleware which should be replaced
})
it('Current period end is modified')
it('An invoice for the new starting period is generated')
it('Subscription status keeps active')
})
上下文(请填写以下信息):
全部运行在节点 8 上,我正在 运行 使用 mocha 进行测试并使用 dirty chai 进行设置。
这些是我的开发依赖项:
"devDependencies": {
"base64url": "^2.0.0",
"cross-env": "^5.0.5",
"decache": "^4.4.0",
"dirty-chai": "^2.0.1",
"faker": "^4.1.0",
"google-auth-library": "^0.12.0",
"googleapis": "^23.0.0",
"minimist": "^1.2.0",
"mocha": "^5.2.0",
"nodemon": "^1.12.0",
"nyc": "^11.2.1",
"sinon": "^6.1.5",
"standard": "^10.0.3",
"stripe-local": "^0.1.1"
}
未决问题
根据经验,应该在每个测试中设置存根,即在 beforeEach
或 it
中,而不是在 before
中。在这里,它们似乎不包含每个测试逻辑,但它们可以,在这种情况下,它们将无法按预期使用 before
。 mocha-sinon
最好用于将 Mocha 与 Sinon 沙箱集成,因此不需要 afterEach
来恢复存根,这是自动完成的。
由于 verifySignature
是导出 属性 而不是导出本身,因此 signatureMiddleware
模块可能会保留原样,但使用它的模块应该被取消缓存并重新导入在他们预期使用 verifySignature
的测试中。如果整个测试套件的行为应该相同,那么也应该在 beforeEach
中执行。例如。如果直接在app
模块中使用这些中间件,则为:
const decache = require('decache');
...
describe(() => {
let app;
beforeEach(() => {
verifySignatureStub = sinon.stub(signatureMiddleware, 'verifySignature');
...
});
beforeEach(() => {
decache('./app');
app = require('./app');
});