如何使用Mocha测试返回匿名函数的Express授权中间件?
授权中间件单元测试实现方案
要测试你的授权中间件,核心是模拟Express中间件依赖的req、res、next对象,然后验证中间件的行为是否符合预期。下面是具体的测试步骤和代码示例:
测试核心逻辑
authorizeStrategy返回的是一个(req, res, next)格式的函数,测试时需要:
- 构造包含
USER.role的req对象,模拟当前登录用户的角色 - 用Sinon Stub模拟
res的status和json方法(支持链式调用) - 用Sinon Spy模拟
next函数,验证是否被调用
完整测试代码
const sinon = require('sinon'); const authorizeMiddleware = require('../../middleware/authorize'); describe('Authorize Middleware Tests', function() { let req; let res; let next; beforeEach(function() { // 初始化基础模拟对象 req = { USER: { id: 1, role: 'admin' } }; // 模拟res对象,支持status().json()链式调用 res = { status: sinon.stub().returnsThis(), json: sinon.stub() }; // 用Spy监控next函数 next = sinon.spy(); }); it('调用next当用户角色匹配时', function() { const authorize = authorizeMiddleware.authorizeStrategy('admin'); authorize(req, res, next); // 验证next被调用,res的方法未触发 sinon.assert.calledOnce(next); sinon.assert.notCalled(res.status); sinon.assert.notCalled(res.json); }); it('返回403当用户角色不匹配时', function() { req.USER.role = 'user'; const authorize = authorizeMiddleware.authorizeStrategy('admin'); authorize(req, res, next); // 验证返回403和正确的错误消息 sinon.assert.calledWith(res.status, 403); sinon.assert.calledWith(res.json, { message: 'Unauthorized' }); // next未被调用 sinon.assert.notCalled(next); }); it('允许所有用户访问当未传入roles参数时', function() { const authorize = authorizeMiddleware.authorizeStrategy(); authorize(req, res, next); sinon.assert.calledOnce(next); sinon.assert.notCalled(res.status); }); it('调用next当用户角色在指定角色数组内时', function() { const authorize = authorizeMiddleware.authorizeStrategy(['admin', 'moderator']); authorize(req, res, next); sinon.assert.calledOnce(next); }); it('返回403当用户角色不在指定角色数组内时', function() { req.USER.role = 'guest'; const authorize = authorizeMiddleware.authorizeStrategy(['admin', 'moderator']); authorize(req, res, next); sinon.assert.calledWith(res.status, 403); sinon.assert.calledWith(res.json, { message: 'Unauthorized' }); sinon.assert.notCalled(next); }); });
关键细节说明
- 链式调用处理:
res.status().json()是链式调用,所以用sinon.stub().returnsThis()让status方法返回res本身,确保链式调用能正常执行。 - 独立测试:不需要依赖认证中间件的Stub,直接构造
req.USER即可,避免测试耦合,让每个测试只关注授权逻辑本身。 - Sinon断言:使用
sinon.assert系列方法验证函数调用情况,比手动判断更精准可靠。
内容的提问来源于stack exchange,提问作者Mathieu Thauvoye
相关产品推荐
相关产品推荐

