如何在Jest单元测试中Mock Express路由中的db.getUsers函数?
解决Express路由测试中Mock依赖失效的问题
问题根源
你的测试代码存在三个核心问题:
- 错误直接调用
app.get():Express的app.get()是用来注册路由的方法,无法直接发起HTTP请求,需要用专门的HTTP测试工具。 - Mock时机错误:在引入
userRoute.js之后才Mockdb模块,此时路由已经加载了原始的db.getUsers引用,后续Mock无法生效。 - 缺少必要的模块引入:测试代码中未引入
express模块。
解决步骤
1. 安装测试依赖
首先安装supertest,它是专门用于测试Express HTTP接口的工具:
npm install --save-dev supertest
2. 修正测试代码(推荐方案:使用jest.mock)
核心逻辑是先Mockdb模块,再加载路由和Express实例,确保路由使用的是Mock后的db引用:
const express = require("express"); const request = require("supertest"); // 提前Mock整个db模块 jest.mock('./db', () => ({ getUsers: jest.fn() })); const db = require('./db'); const router = require("./userRoute.js"); const app = express(); app.use(express.json()); // 可选:解析JSON请求,适配多数场景 app.use("/", router); describe("Users Route", () => { test("getUsers Happy Path", async () => { // 设置Mock的异步返回值 db.getUsers.mockResolvedValue({ id: 12345, name: "Jason", age: "34" }); // 用supertest发起真实的HTTP请求模拟 const response = await request(app).get("/users/"); // 断言响应结果 expect(response.statusCode).toBe(200); expect(response.body).toEqual({ status: 200, data: { id: 12345, name: "Jason", age: "34" } }); // 验证Mock函数被正确调用 expect(db.getUsers).toHaveBeenCalledTimes(1); }); });
3. 备选方案:使用jest.spyOn
如果偏好使用spyOn,同样要保证Mock时机在路由加载之前:
const express = require("express"); const request = require("supertest"); const db = require('./db'); // 在引入路由前,先Spy并Mock目标方法 jest.spyOn(db, "getUsers").mockResolvedValue({ id: 12345, name: "Jason", age: "34" }); const router = require("./userRoute.js"); const app = express(); app.use("/", router); describe("Users Route", () => { test("getUsers Happy Path", async () => { const response = await request(app).get("/users/"); expect(response.statusCode).toBe(200); expect(response.body.data).toEqual({ id: 12345, name: "Jason", age: "34" }); expect(db.getUsers).toHaveBeenCalled(); }); });
关键注意事项
- 模块缓存机制:Node.js会缓存已加载的模块,因此必须在加载依赖目标模块的文件(这里是
userRoute.js)之前完成Mock。 - 异步Mock处理:因为
db.getUsers是被await调用的异步函数,必须使用mockResolvedValue返回Promise,或在mockImplementation中手动返回Promise.resolve(...)。 - HTTP请求模拟:必须用
supertest这类工具模拟请求,Express实例本身不提供发起请求的能力。
内容的提问来源于stack exchange,提问作者beep
相关产品推荐
相关产品推荐

