在setupTests中初始化Backend类时,Jest模拟axios失效问题
问题原因与解决方案
核心问题:模块缓存导致Backend引用未Mock的axios
当你在setupTests.js中提前创建Backend实例时,Node.js的模块缓存机制会保留Backend首次加载时引用的原始axios实例。后续测试文件中通过jest.mock("axios")生成的Mock axios,无法替换Backend内部已经绑定的原始axios。这就导致测试中调用getList时,实际执行的是原始axios的get方法,而非你设置的Mock函数,最终触发stub未被调用的断言失败。
解决方案
方案1:在setupTests中提前Mock axios
确保setupTests.js在创建Backend实例前就Mock axios,让Backend从一开始就引用Mock版本的axios:
import "@testing-library/jest-dom"; import axios from "axios"; import {Backend} from "./shared/utils/backend"; // 提前Mock axios,覆盖全局模块 jest.mock("axios"); // 可按需给get方法设置默认Mock实现 jest.spyOn(axios, 'get').mockResolvedValue({ data: [] }); new Backend("test");
方案2:给Backend添加axios依赖注入(推荐)
修改Backend类,允许在构造函数中传入自定义axios实例,彻底解耦模块依赖,从根源避免缓存问题:
import axios from "axios"; export class Backend { private _baseUrl: string; private _axios; // 新增可选参数,默认使用全局axios constructor(baseUrl: string, axiosInstance = axios) { this._axios = axiosInstance; this._axios.defaults.headers.get["Access-Control-Allow-Origin"] = "*"; this._axios.defaults.headers.get["Access-Control-Allow-Credentials"] = "true"; this._baseUrl = baseUrl; } async getList(url: string): Promise<any[] | undefined> { // 使用实例化的_axios而非全局axios const data = await this._axios.get<any[]>(`${this._baseUrl}/${url}`); return data?.data; } }
测试文件中直接传入Mock的axios:
import {Backend} from "../../../shared/utils/backend"; import axios from "axios"; jest.mock("axios"); describe("backend", () => { test("When getList is called data is returned", async () => { const mockGet = jest.fn().mockResolvedValue({ data: [{ prop: "test", otherProp: 2 }] }); (axios.get as jest.Mock) = mockGet; // 传入Mock的axios实例 const backend = new Backend("baseUrl", axios); const data = await backend.getList("testUrl"); expect(mockGet).toHaveBeenCalledWith("baseUrl/testUrl"); expect(data).toHaveLength(1); }); });
setupTests中创建实例时也可传入Mock axios:
import "@testing-library/jest-dom"; import axios from "axios"; import {Backend} from "./shared/utils/backend"; jest.mock("axios"); new Backend("test", axios);
方案3:测试前清除模块缓存
通过jest.resetModules()清除模块缓存,让测试文件重新加载Backend和axios,确保Backend引用Mock的axios:
describe("backend", () => { beforeEach(() => { // 每次测试前重置模块缓存 jest.resetModules(); }); test("When getList is called data is returned", async () => { // 重新Mock axios并导入Backend jest.mock("axios"); const axios = require("axios").default; const { Backend } = require("../../../shared/utils/backend"); const mockGet = jest.fn().mockResolvedValue({ data: [{ prop: "test", otherProp: 2 }] }); (axios.get as jest.Mock) = mockGet; const backend = new Backend("baseUrl"); const data = await backend.getList("testUrl"); expect(mockGet).toHaveBeenCalledWith("baseUrl/testUrl"); expect(data).toHaveLength(1); }); });
此方案需手动重新导入模块,操作繁琐,仅作为临时替代方案。
内容的提问来源于stack exchange,提问作者Rick Hoving
相关产品推荐
相关产品推荐

