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

Node.js API测试:Supertest调用时Mock函数未生效问题排查

问题原因

Node.js 的模块缓存机制导致了这个问题:当你在测试文件中先导入 app,app 会加载 wishlistsController,而 wishlistsController 会提前导入并缓存原始的 getWishlists 函数。之后你通过 jest.spyOn 对服务函数进行的 Mock,不会影响到控制器中已经缓存的函数引用。

另外,你的 Mock 没有贴合原函数的异步特性(虽然 await 可以处理非 Promise 值,但建议使用 mockResolvedValue 保持行为一致)。

修复方案

方案一:调整导入顺序,先 Mock 再加载 App

将 app 的导入移到 Mock 设置之后,确保控制器加载的是已经被 Mock 后的服务函数:

const supertest = require("supertest")

describe("Testing Wishlist Apis ", () => {
    it("should return 200 for wishlists fetch", async () => {
        const payload = "Some Mock Value"

        // 先导入服务并设置 Mock
        const WishlistService = require("../services/wishlist.service")
        const getWishlistsMock = jest.spyOn(WishlistService, "getWishlists")
        // 使用 mockResolvedValue 模拟异步返回
        getWishlistsMock.mockResolvedValue(payload);

        // 再导入 App,确保控制器加载的是 Mock 后的服务
        const { app } = require('../index.js')

        const { statusCode, body } = await supertest(app)
          .get("/wishlists")
          .set('Content-Type', 'application/json')
          .send();

        expect(body).toEqual(payload);
        expect(statusCode).toBe(200);
        
        // 测试完成后恢复原始函数
        getWishlistsMock.mockRestore();
    })
})

方案二:使用 jest.mock 直接 Mock 整个服务模块

这种方式更可靠,能确保所有模块加载的都是 Mock 后的服务:

const supertest = require("supertest")
const WishlistService = require("../services/wishlist.service")

// 提前 Mock 整个服务模块
jest.mock("../services/wishlist.service", () => ({
    getWishlists: jest.fn()
}))

// 导入 App(此时加载的控制器会使用 Mock 后的服务)
const { app } = require('../index.js')

describe("Testing Wishlist Apis ", () => {
    it("should return 200 for wishlists fetch", async () => {
        const payload = "Some Mock Value"
        // 设置 Mock 的返回值
        WishlistService.getWishlists.mockResolvedValue(payload);

        const { statusCode, body } = await supertest(app)
          .get("/wishlists")
          .set('Content-Type', 'application/json')
          .send();

        expect(body).toEqual(payload);
        expect(statusCode).toBe(200);
        // 验证函数是否被调用
        expect(WishlistService.getWishlists).toHaveBeenCalled();
    })
})
关键注意点
  • 模块缓存:Node.js 会缓存已导入的模块,所以 Mock 必须在目标模块(这里是控制器和 App)加载前设置。
  • 异步函数 Mock:对于异步函数,优先使用 mockResolvedValue 或 mockRejectedValue 来模拟返回值,确保与原函数的行为一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 19:57:50