如何使用Jest和SuperTest Mock Express中间件类方法?
问题根源
你的verifyAuthenticated是类的箭头函数属性,这种属性在类实例化时就会被赋值给实例对象。而app.ts在启动时就导入了authMiddleware实例,并直接把verifyAuthenticated的引用绑定到了路由上。后续用jest.spyOn去mock这个属性时,路由里使用的还是最初加载的那个原函数引用,所以mock没有生效。
解决方案
方案1:将箭头函数改为原型方法
把verifyAuthenticated从箭头函数属性改成类的原型方法,这样Jest可以正确mock原型上的方法,不管实例何时创建,调用的都是原型上的方法,mock会覆盖原实现。
修改AuthMiddleware.ts:
import { Request, Response, NextFunction } from "express"; class AuthMiddleware { constructor() { console.log("AuthMiddleware instance created"); } // 移除箭头,改为原型方法 verifyAuthenticated(request: Request, response: Response, next: NextFunction) { console.log("This is the real deal"); next(); }; } export default new AuthMiddleware();
测试代码无需修改,运行后会打印This is the mock deal,mock生效。
方案2:先Mock再导入App
如果不想修改类的方法类型,需要确保在mockverifyAuthenticated之后再导入app,避免app提前绑定原函数的引用。
修改测试文件:
import request from "supertest"; import authMiddleware from "../src/AuthMiddleware"; import { NextFunction, Request, Response } from "express"; describe("GET /", () => { test("Should return online.", async () => { // 先完成mock jest .spyOn(authMiddleware, "verifyAuthenticated") .mockImplementation((req: Request, res: Response, next: NextFunction) => { console.log("This is the mock deal"); next(); }); // 延迟导入app,此时会使用mock后的方法 const { default: app } = await import("../src/app"); const agent = request(app); const response = await agent.get("/").send(); expect(response.statusCode).toBe(200); expect(response.headers["content-type"]).toContain("application/json"); expect(response.body.status).toBe("online"); }); });
方案3:Mock整个AuthMiddleware模块
直接mock整个模块,让app导入的就是mock后的实例,从根源上替换原方法。
修改测试文件:
import request from "supertest"; import { NextFunction, Request, Response } from "express"; // 提前mock整个AuthMiddleware模块 jest.mock("../src/AuthMiddleware", () => { const mockVerify = (req: Request, res: Response, next: NextFunction) => { console.log("This is the mock deal"); next(); }; return { default: { verifyAuthenticated: mockVerify } }; }); // 导入app,此时已使用mock后的模块 import app from "../src/app"; describe("GET /", () => { test("Should return online.", async () => { const agent = request(app); const response = await agent.get("/").send(); expect(response.statusCode).toBe(200); expect(response.headers["content-type"]).toContain("application/json"); expect(response.body.status).toBe("online"); }); });
内容的提问来源于stack exchange,提问作者user16197389
相关产品推荐
相关产品推荐

