You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:00:18