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

Node.js ESM环境下如何Stub默认导出的Auth中间件?

问题分析与解决方案

错误原因拆解

  1. 第一种方法报错:sinon.stub(auth()).callsFake(...) 逻辑错误。你先调用了auth()得到实际的中间件函数,再试图给这个临时函数打 stub,但这个函数和路由中使用的中间件引用无关,而且sinon.stub(函数)返回的存根函数不需要用callsFake——我们需要的是让auth()本身返回模拟中间件,而非修改已生成的中间件行为。
  2. 第二种方法报错:import auth from '../../middlewares/auth.js' 导入的auth就是默认导出的函数本身,不是包含default属性的模块对象,所以sinon.replace(auth, 'default')会提示属性不存在。
  3. 核心问题:你在before中提前创建了app并加载了路由,此时路由已经调用auth()生成了实际中间件,后续在beforeEach中做的 stub 无法影响已初始化的中间件。

正确解决方案

调整测试生命周期,在创建应用和路由之前完成 stub,同时正确存根auth函数,让它返回直接执行next()的模拟中间件:

import express from 'express';
import supertest from 'supertest';
import { router } from "express-file-routing"
import auth from '../../middlewares/auth.js';
import sinon from 'sinon'

describe("/foo", () => {
    let app, request;
    
    // 将app创建移到beforeEach,确保每次测试都用最新的stub
    beforeEach(async () => {
        // 存根auth函数,让它返回跳过验证的中间件
        const authStub = sinon.stub(auth).returns((req, res, next) => next());

        // 重新创建app并加载路由(此时路由会使用stub后的auth)
        app = express();
        app.use("/", await router())
        request = supertest(app);

        // 测试结束后恢复原函数
        return () => authStub.restore();
    });

    // 示例测试用例
    it("should bypass auth middleware successfully", async () => {
        const res = await request.get("/foo");
        // 你的断言逻辑,比如验证响应状态码等
        expect(res.status).toBe(200);
    });
});

如果遇到 ES 模块只读属性无法直接 stub 的问题,可以改用sinon.replace替换整个auth函数:

beforeEach(async () => {
    // 定义模拟的auth生成函数
    const mockAuth = () => (req, res, next) => next();
    // 替换原auth函数
    sinon.replace(auth, mockAuth);

    app = express();
    app.use("/", await router())
    request = supertest(app);

    return () => sinon.restore();
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 19:52:02