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

如何使用Jest测试Node.js身份验证中间件?

如何用Jest测试Node.js身份验证中间件并模拟请求头?

你的测试代码无法运行,核心问题是没有正确模拟req、res对象的方法,也没处理JWT验证和环境变量的依赖。下面是完整的解决方案,分场景覆盖你的中间件逻辑:

1. 基础准备:模拟req、res和next

首先要给req添加header方法,给res添加status、json、send这些Express响应方法,用Jest的jest.fn()创建模拟函数,方便后续断言调用情况。

2. Mock依赖:JWT和环境变量

因为我们不需要真实的JWT验证,所以用Jest mock掉jsonwebtoken的verify方法,同时设置测试用的process.env.TOKEN_SECRET。

完整测试代码

import verifyToken from '../middleware/verifyToken';
import jwt from 'jsonwebtoken';

// Mock jsonwebtoken模块
jest.mock('jsonwebtoken');

describe('verifyToken middleware', () => {
  // 测试前设置环境变量
  beforeEach(() => {
    process.env.TOKEN_SECRET = 'test-secret';
  });

  // 场景1:请求头没有token,返回401
  test('returns 401 when no token is provided', () => {
    // 模拟req:header方法返回undefined
    const req = {
      header: jest.fn().mockReturnValue(undefined)
    };
    // 模拟res:status返回自身,支持链式调用
    const res = {
      status: jest.fn().mockReturnThis(),
      json: jest.fn()
    };
    const next = jest.fn();

    verifyToken(req, res, next);

    expect(req.header).toHaveBeenCalledWith('x_auth-token');
    expect(res.status).toHaveBeenCalledWith(401);
    expect(res.json).toHaveBeenCalledWith({ message: 'Access denied' });
    expect(next).not.toHaveBeenCalled();
  });

  // 场景2:token无效,返回400
  test('returns 400 when invalid token is provided', () => {
    const mockToken = 'invalid-token';
    const req = {
      header: jest.fn().mockReturnValue(mockToken)
    };
    const res = {
      status: jest.fn().mockReturnThis(),
      send: jest.fn()
    };
    const next = jest.fn();

    // 让jwt.verify抛出错误,模拟无效token
    jwt.verify.mockImplementation(() => {
      throw new Error('Invalid token');
    });

    verifyToken(req, res, next);

    expect(jwt.verify).toHaveBeenCalledWith(mockToken, process.env.TOKEN_SECRET);
    expect(res.status).toHaveBeenCalledWith(400);
    expect(res.send).toHaveBeenCalledWith('Invalid Token');
    expect(next).not.toHaveBeenCalled();
  });

  // 场景3:token有效,调用next并设置req.user
  test('sets req.user and calls next when valid token is provided', () => {
    const mockToken = 'valid-token';
    const mockUser = { id: '123', username: 'test-user' };
    const req = {
      header: jest.fn().mockReturnValue(mockToken)
    };
    const res = {
      status: jest.fn().mockReturnThis(),
      json: jest.fn(),
      send: jest.fn()
    };
    const next = jest.fn();

    // 让jwt.verify返回模拟的用户信息
    jwt.verify.mockReturnValue(mockUser);

    verifyToken(req, res, next);

    expect(jwt.verify).toHaveBeenCalledWith(mockToken, process.env.TOKEN_SECRET);
    expect(req.user).toEqual(mockUser);
    expect(next).toHaveBeenCalled();
    expect(res.status).not.toHaveBeenCalled();
  });
});

关键说明

  • 模拟req.header:通过jest.fn().mockReturnValue()控制返回的token值,覆盖不同场景。
  • 链式调用模拟:res的status方法用mockReturnThis(),保证res.status(401).json(...)的链式调用不会报错。
  • JWT Mock:用jest.mock('jsonwebtoken')接管整个模块,通过mockImplementation或mockReturnValue控制verify的行为,模拟成功/失败情况。
  • 环境变量:在beforeEach里设置测试用的TOKEN_SECRET,避免依赖真实环境变量。

内容的提问来源于stack exchange,提问作者McDavid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 21:05:22