如何用Jest动态Mock axios create实现多测试用例?
解决Jest动态Mock Axios时出现的"Cannot read properties of undefined (reading 'then')"错误
错误原因
你的动态Mock逻辑存在两个核心问题:
- Mock返回值不符合Axios真实行为:真实的Axios实例调用后会返回一个
Promise,但你当前的Mock直接返回了普通数据对象,导致代码中调用.then()或使用await时,因普通对象没有then方法抛出错误。 - 模块加载时机错误:使用
jest.doMock时,若静态导入useSubscriptionStore,会导致store在Mock生效前就加载了真实的Axios,Mock无法生效。
解决方案1:修正动态Mock并配合动态导入
调整mockAxios函数,让Mock返回Promise,同时在测试用例中动态导入依赖模块:
const mockAxios = (data) => { jest.doMock('axios', () => ({ // 创建的Axios实例调用后返回resolved状态的Promise create: jest.fn(() => jest.fn(() => Promise.resolve(data))), })); }; describe('Subscription store', () => { beforeEach(() => { jest.resetModules(); }); it('fetches premium subscription data', async () => { // 保持和原接口一致的两层data结构 const mockResponse = { data: { data: { subscription: [ { tag: 'premium' }, ], }, }, }; mockAxios(mockResponse); // 动态导入store,确保Mock生效后再加载模块 const { useSubscriptionStore } = await import('./path-to-your-store-file'); const subscription = useSubscriptionStore(); await subscription.fetch(); // 添加断言验证结果 expect(subscription.subscription).toEqual([{ tag: 'premium' }]); }); });
解决方案2:更简洁的全局Mock+动态修改返回值
这种写法不需要重置模块和动态导入,适合大多数场景:
// 提前全局Mock axios,返回一个空的mock实例函数 jest.mock('axios', () => ({ create: jest.fn(() => jest.fn()), })); // 提取mock的Axios实例函数,方便后续修改返回值 const mockAxiosInstance = require('axios').create.mockReturnValue(); describe('Subscription store', () => { beforeEach(() => { // 每个测试用例前重置mock,避免用例间污染 mockAxiosInstance.mockReset(); }); it('fetches free subscription data', async () => { // 设置当前用例的返回值 mockAxiosInstance.mockResolvedValue({ data: { data: { subscription: [{ tag: 'free' }], }, }, }); const subscription = useSubscriptionStore(); await subscription.fetch(); expect(subscription.subscription).toEqual([{ tag: 'free' }]); }); it('fetches premium subscription data', async () => { // 设置另一个用例的返回值 mockAxiosInstance.mockResolvedValue({ data: { data: { subscription: [{ tag: 'premium' }], }, }, }); const subscription = useSubscriptionStore(); await subscription.fetch(); expect(subscription.subscription).toEqual([{ tag: 'premium' }]); }); });
内容的提问来源于stack exchange,提问作者Dr. Junior
相关产品推荐
相关产品推荐

