Node.js单元测试:如何在请求中设置Session通过接口鉴权?
解决方案:测试带express-session的路由
首先得明确你之前的操作哪里出了问题:
- 你直接在
app.use(session({accessToken: 'ssshhhhh'}))里加accessToken是错的,这个配置对象是用来初始化session中间件的(比如设置secret、cookie规则),不是用来设置具体的session数据。 - 用
set('cookie', ['accessToken=sssh'])也无效,因为express-session里的accessToken是存在服务器端的session存储中的,前端cookie里只有session ID,服务器通过这个ID找到对应的session数据。
下面两种可行的测试方案,你可以根据需求选择:
方案1:用supertest的Agent维持会话(推荐集成测试)
supertest的agent会自动保存和发送cookie,完美模拟用户的会话流程,适合测试整个路由的集成逻辑。
步骤1:确保express-session的测试配置正确
先修正你的session中间件配置,测试环境必须要有secret(用于签名session ID cookie):
const session = require('express-session'); // 测试环境的session配置 app.use(session({ secret: 'your-test-secret-key', // 必填项,随便填一个字符串就行 resave: false, saveUninitialized: false, cookie: { secure: false, // 测试环境不需要HTTPS,设为false httpOnly: true } }));
步骤2:编写集成测试代码
const request = require('supertest'); const { expect } = require('chai'); const app = require('../path/to/your/app'); describe('GET /myapp/profile', () => { // 测试:当session中有accessToken时,成功返回Profile it('returns 200 and profile data when accessToken exists', (done) => { // 创建一个agent实例,用于维持会话 const agent = request.agent(app); // 先通过一个临时接口设置session里的accessToken(模拟用户登录后的状态) agent.get('/test-set-session') .end((err) => { if (err) return done(err); // 现在agent已经持有包含有效session的cookie,请求目标路由 agent.get('/myapp/profile') .expect(200) .end((err, res) => { if (err) return done(err); // 根据你的控制器返回内容,添加断言 expect(res.body).to.have.property('username'); // 示例断言 done(); }); }); }); // 测试:当session中没有accessToken时,返回403 it('returns 403 when accessToken is missing', (done) => { request(app) .get('/myapp/profile') .expect(403, done); }); }); // 在你的app中添加临时测试路由(测试完可以删掉,或者只在测试环境加载) if (process.env.NODE_ENV === 'test') { app.get('/test-set-session', (req, res) => { req.session.accessToken = 'ssshhhhh'; // 直接设置session数据 res.sendStatus(200); }); }
方案2:Mock req.session(适合单元测试中间件或控制器)
如果你只想单独测试中间件逻辑,或者不想依赖session存储,可以用node-mocks-http直接模拟request对象,或者用sinon stub中间件。
测试中间件逻辑
const { expect } = require('chai'); const sinon = require('sinon'); const httpMocks = require('node-mocks-http'); const myProfileMiddleware = require('../path/to/myProfileMiddleware'); describe('checkAccessToken Middleware', () => { it('calls next() when accessToken exists in session', () => { // 创建模拟的req、res和next函数 const req = httpMocks.createRequest({ session: { accessToken: 'valid-token' } }); const res = httpMocks.createResponse(); const next = sinon.spy(); // 执行中间件 myProfileMiddleware.checkAccessToken()(req, res, next); // 断言next被调用 expect(next.calledOnce).to.be.true; }); it('returns 403 when accessToken is missing', () => { const req = httpMocks.createRequest({ session: {} // 空session,没有accessToken }); const res = httpMocks.createResponse(); const next = sinon.spy(); myProfileMiddleware.checkAccessToken()(req, res, next); // 断言返回403,且next未被调用 expect(res.statusCode).to.equal(403); expect(next.called).to.be.false; }); });
测试路由集成(Mock中间件)
如果你想测试路由是否正确调用控制器,可以stub中间件,直接注入有效的session:
const request = require('supertest'); const { expect } = require('chai'); const sinon = require('sinon'); const app = require('../path/to/your/app'); const myProfileMiddleware = require('../path/to/myProfileMiddleware'); describe('GET /myapp/profile', () => { let stubMiddleware; beforeEach(() => { // Stub中间件,让它直接设置有效session并调用next stubMiddleware = sinon.stub(myProfileMiddleware, 'checkAccessToken').returns((req, res, next) => { req.session = { accessToken: 'valid-token' }; next(); }); }); afterEach(() => { // 恢复stub,避免影响其他测试 stubMiddleware.restore(); }); it('calls getProfile controller when accessToken is valid', (done) => { // Stub控制器方法,验证是否被调用 const stubController = sinon.stub(require('../path/to/myProfileController'), 'getProfile') .callsFake((req, res) => { res.status(200).json({ profile: 'test-user' }); }); request(app) .get('/myapp/profile') .expect(200) .end((err) => { if (err) return done(err); expect(stubController.calledOnce).to.be.true; stubController.restore(); done(); }); }); });
关键注意事项
- 你的Node版本8.7比较老,确保所有依赖版本兼容:supertest@3.0.0和express-session的兼容没问题,但要注意
node-mocks-http@1.6.6的API和最新版一致。 - 如果你的app用了自定义的session存储(比如Redis),测试时可以改用内存存储(默认就是内存,适合测试),避免依赖外部服务。
内容的提问来源于stack exchange,提问作者user2986749
相关产品推荐
相关产品推荐

