【发布时间】:2020-07-29 18:26:01
【问题描述】:
我已经在我的应用程序中实现了“express-rate-limit”作为特定端点的中间件。在单元测试方面,我在尝试对这个中间件进行存根以适当地控制响应时遇到了麻烦。
例如,我有一个每 15 分钟允许 3 个请求的路由,但是,我有 10 个针对该路由的单元测试。前 3 个测试按预期通过,接下来的 7 个测试返回 '429 Too Many Requests' 响应。
'express-rate-limit' 库似乎被强烈建议用于速率限制,但是,我找不到任何关于如何在测试环境中使用它的信息。
下面显示了简化的实现尝试。
ratelimit.js
exports.createUser = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minute
max: 3,
message: 'Too many requests',
statusCode: 429
})
route.js
const rateLimits = require('./ratelimit')
let incorrect = function (res, msg) {
res.status(401)
res.send({
status: 'err',
payload: {
msg: msg
}
})
}
router.post('/create', rateLimits.createUser, (req, res) => {
if (!req.body.email) return incorrect(res, 'Email not provided')
userController
.createUser(req.body.email)
.then(user => {
if (!user) incorrect(res, 'User not created')
else correct(res)
})
.catch(() => incorrect(res, 'Internal Error'))
})
test.js
这应该将速率限制存根,只允许发出一个请求,这意味着第二个测试应该失败。但是第二个测试将通过,因为它从未被调用(根据 'real' 实现,速率限制仍然为 3)
const rateLimits = require('./ratelimit')
const userController = require('./usercontroller')
let server
let limiter
describe('Users', () => {
before(() => {
limiter = sinon.stub(rateLimits, 'createUser').callsFake(() => rateLimit({
windowMs: 15 * 60 * 1000, // 15 minute
max: 1,
message: 'Too many requests',
statusCode: 429
}))
server = require('../app')
})
it('should return an error for invalid email', done => {
chai.request(server)
.post('/users/create')
.send({
email: 'notanemail'
})
.end((err, res) => {
res.should.have.status(401)
res.body.status.should.equal('err')
done()
})
})
it('should return an error for missing parameter', done => {
chai.request(server)
.post('/users/create')
.send({})
.end((err, res) => {
res.should.have.status(401)
res.body.status.should.equal('err')
done()
})
})
})
这个问题Stubbing Out Middleware 强调应该在执行存根后初始化应用程序本身,以确保正确加载。这似乎不起作用,在文件顶部创建导入的标准 .implementation 也不起作用。
另外,出于测试目的,我尝试在执行时将一些文本记录到控制台,以确保调用存根函数。该函数似乎永远不会被调用,因为日志永远不会打印到控制台。
limiter = sinon.stub(rateLimits, 'createUser').callsFake(() => console.log("I was executed"))
我尝试的另一个失败的替代方法是直接调用 express-rate-limit 模块
const rateLimit = require('express-rate-limit')
limiter = sinon.stub(rateLimit.prototype, 'constructor').callsFake(() => rateLimit({
windowMs: 15 * 60 * 1000, // 15 minute
max: 1,
message: 'Too many requests',
statusCode: 429
}))
【问题讨论】:
-
好问题!感谢您提供所有详细信息。感谢您参考您尝试过的其他事情和其他 SO 答案。我希望所有问题都写得这么好!
-
@Hydralore 你能找到解决方案吗,我的问题是相关的,尽管我能够模拟 rateLimit 本身,我正在使用的存储(即 memcache-store)在单元中引起一些问题测试。如果您能分享您是如何实现这一目标的,将不胜感激。谢谢
标签: javascript node.js unit-testing