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

如何Mock Redux Thunk异步Action返回值用于组件测试(仅函数Mock无真实请求)

正确实现方案

你当前的错误主要来自3个问题:

  • 对createAsyncThunk生成的异步thunk函数的mock格式错误,thunk函数调用后会返回一个接收dispatch作为参数的嵌套函数,你直接返回了action对象,无法被dispatch正常执行
  • 多余的spyOn操作,setTestData不是TestPage的导出项,你不需要对它做spy处理
  • 渲染组件的逻辑放在了waitFor内部,执行顺序错误

正确的mock和测试代码

首先修改mock逻辑,让它返回符合thunk规范的函数,注意匹配原模块的默认导出格式:

// 直接mock整个testService模块
jest.mock('../redux/asyncServices/testService', () => {
  // 模拟createAsyncThunk生成的thunk函数
  const mockSetTestData = () => async (dispatch) => {
    dispatch({
      type: "setTestData/fulfilled",
      payload: {
        user: {name: 'Loaded user name'}
      }
    })
  };
  // 匹配原模块的ES默认导出规则
  return {
    __esModule: true,
    default: mockSetTestData
  };
});

然后修改测试用例逻辑:

import TestPage from '../pages/TestPage';
import {screen, waitFor} from '@testing-library/react';

describe('Timesheet Menu page tests', () => {
  beforeEach(() => {
    matchMedia = new MatchMediaMock()
  })

  afterEach(() => {
    matchMedia.clear()
    jest.clearAllMocks()
  })

  test('Component renders correctly', async () => {
    // 先渲染组件,触发useEffect里的dispatch逻辑
    renderWithRedux(<TestPage/>, {initialState})
    // 等待异步thunk执行完成,用户名渲染
    await waitFor(() => {
      expect(screen.getByText('Loaded user name')).toBeInTheDocument()
    })
    expect(screen.getByText('Test')).toBeInTheDocument()
  })
})

补充优化点

如果你的reducer对pending状态也做了处理,mock的时候可以加上pending状态的dispatch,更贴近真实的异步流程:

const mockSetTestData = () => async (dispatch) => {
  dispatch({type: "setTestData/pending"})
  await new Promise(resolve => setTimeout(resolve, 0))
  dispatch({
    type: "setTestData/fulfilled",
    payload: {user: {name: 'Loaded user name'}}
  })
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 15:54:02