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

Jest测试时如何为每个用例获取axiosInstance的新实例?

问题根因

你遇到的问题本质是ES 模块的顶层初始化逻辑仅会在首次导入时执行一次:你的业务代码中const fetcher = axiosInstance()属于模块顶层代码,测试文件导入业务模块的瞬间就会执行该逻辑,生成固定的fetcher实例。后续你修改axiosInstance的mock实现,也不会改变已经创建完成的fetcher实例,因此失败用例依然会走首次的成功mock逻辑。

解决方法

下面提供3种可行的修复方案,你可以根据实际场景选择:

方案1:复用get的mock函数(改动最小,无需修改业务代码)

调整jest.mock的结构,把axios实例的get方法绑定为全局可修改的单一mock函数,后续测试用例直接修改该函数的返回行为即可:

// 测试文件顶部提前声明可复用的get mock
const mockGet = jest.fn();

jest.mock('../../src/utils/network', () => {
  const axiosInstance = jest.fn().mockImplementation(() => {
    return {
      get: mockGet, // 所有axios实例的get都复用同一个mock函数
    };
  }) as any;
  axiosInstance.configure = jest.fn();
  return axiosInstance;
});

// 测试用例内直接修改mockGet的行为
describe('test LOGOUT', () => {
  beforeEach(() => {
    store.clearActions();
    mockGet.mockReset(); // 每次用例前重置get的mock状态
  });

  it('should test be success', async () => {
    mockGet.mockResolvedValue({ headers: {} }); // 模拟成功返回
    await store.dispatch({
      type: 'LOGOUT',
      payload: { userName: 'testUserName' },
    });
    expect(store.getActions()).toContainEqual({ type: 'LOGOUT_SUCCESS' });
  });

  it('should test be fail', async () => {
    mockGet.mockRejectedValue(new Error('')); // 模拟失败抛出异常
    await store.dispatch({
      type: 'LOGOUT',
      payload: { userName: 'testUserName' },
    });
    expect(store.getActions()).toContainEqual({ type: 'LOGOUT_FAIL' });
  });
});

方案2:重置模块缓存后动态导入(无需修改业务代码,适配复杂场景)

如果你不想调整mock结构,可以通过jest的模块重置能力,让每个测试用例都重新导入业务模块,重新生成fetcher实例:

describe('test LOGOUT', () => {
  let store;
  let fetchMiddleware;
  let axiosInstance;

  beforeEach(() => {
    jest.resetModules(); // 重置所有已导入模块的缓存
    // 动态导入所有依赖,每次都会重新执行业务模块的顶层初始化逻辑
    axiosInstance = require('../../src/utils/network').default;
    fetchMiddleware = require('../../src/你的中间件文件路径').default;
    const thunk = require('redux-thunk').default;
    const configureStore = require('redux-mock-store').default;
    const middlewares = [fetchMiddleware, thunk];
    const mockStore = configureStore(middlewares);
    store = mockStore(getInitialReducerState());
    store.clearActions();
  });

  // 测试用例保持原有逻辑即可,每次都会生成新的fetcher实例
  it('should test be success', async () => {
    await store.dispatch({
      type: 'LOGOUT',
      payload: { userName: 'testUserName' },
    });
    expect(store.getActions()).toContainEqual({ type: 'LOGOUT_SUCCESS' });
  });

  it('should test be fail', async () => {
    (axiosInstance as jest.Mock).mockImplementation(() => {
      return {
        get: jest.fn().mockImplementation(() => {
          throw new Error(' ');
        }),
      };
    });
    await store.dispatch({
      type: 'LOGOUT',
      payload: { userName: 'testUserName' },
    });
    expect(store.getActions()).toContainEqual({ type: 'LOGOUT_FAIL' });
  });
});

方案3:调整业务代码初始化时机(推荐,长期可维护性更高)

把fetcher的初始化从模块顶层移到中间件执行阶段,避免首次导入就生成固定实例:

// 业务代码修改后
import axiosInstance from '~/utils/network';

const fetchMiddleware = () => {
  const fetcher = axiosInstance(); // 每次中间件运行时再生成实例
  switch (type) {
     case 'LOGOUT':{
      try {
          await fetcher.get(API.GET.LOGOUT_OPERATION);
          dispatch({ type: 'LOGOUT_SUCCESS' });
        } catch (err) {
          dispatch({ type: 'LOGOUT_FAIL' });
        }
     }
   }
}

修改后你的原有测试代码无需调整即可正常运行,该方案也方便后续其他场景的测试扩展。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 22:18:00