使用Jest Mock模拟Redux-Thunk函数时触发‘Actions must be plain objects’错误
解决Jest测试Redux-Thunk时的"Actions must be plain objects"错误
你遇到的这个报错本质是测试环境里的dispatch没有Redux-Thunk中间件的支持。看你的代码,functionToMock是一个Redux-Thunk风格的异步action creator(返回函数的函数),而functionToTest里直接把这个函数传给了dispatch——在真实的Redux环境中,Thunk中间件会自动执行这个函数,但你测试时用的mockdispatch只是个普通的jest函数,它只会接收plain object类型的action,自然会报错。
下面给你三个不同场景下的解决方案,你可以根据测试需求选择:
方案1:手动实现支持Thunk的Mock Dispatch
如果不想引入额外依赖,你可以自己写一个能处理Thunk的mock dispatch函数,它会自动判断传入的是函数还是普通action:
// 模拟一个支持Thunk的dispatch const mockDispatch = jest.fn((action) => { // 如果传入的是Thunk函数,就调用它并传入自身 if (typeof action === 'function') { return action(mockDispatch); } // 普通action直接返回 return action; });
然后在测试中使用这个mockDispatch代替普通的jest.fn():
import { functionToTest } from './your-actions-file'; test('functionToTest executes correctly', async () => { await functionToTest()(mockDispatch); // 验证底层的basic action被分发了 expect(mockDispatch).toHaveBeenCalledWith({ type: 'a basic action' }); });
方案2:Mock functionToMock以隔离测试
如果你测试functionToTest的目标只是验证它调用了functionToMock,而不需要关心functionToMock内部的逻辑,可以直接mock这个函数,让它返回一个普通action或者resolved的Promise:
import * as actions from './your-actions-file'; // 保留其他action的真实实现,只mock functionToMock jest.mock('./your-actions-file', () => ({ ...jest.requireActual('./your-actions-file'), functionToMock: jest.fn(() => Promise.resolve({ type: 'MOCKED_ACTION' })) })); test('functionToTest calls functionToMock', async () => { const mockDispatch = jest.fn(); await actions.functionToTest()(mockDispatch); // 验证functionToMock被调用 expect(actions.functionToMock).toHaveBeenCalled(); // 验证dispatch接收了mock的action expect(mockDispatch).toHaveBeenCalledWith({ type: 'MOCKED_ACTION' }); });
方案3:使用redux-mock-store配合Thunk中间件
如果要测试完整的action分发流程(包括多个action的顺序和内容),推荐用redux-mock-store这个库,它可以直接集成Thunk中间件:
首先安装依赖(如果还没装):
npm install redux-mock-store redux-thunk --save-dev
然后编写测试:
import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; import * as actions from './your-actions-file'; // 创建带Thunk中间件的mock store const middlewares = [thunk]; const mockStore = configureMockStore(middlewares); test('functionToTest dispatches all expected actions', async () => { const store = mockStore({}); // 分发functionToTest await store.dispatch(actions.functionToTest()); // 获取所有被分发的action列表 const dispatchedActions = store.getActions(); // 验证basic action在列表中 expect(dispatchedActions).toContainEqual({ type: 'a basic action' }); // 还可以验证其他action的顺序和内容 });
总结
- 如果你需要测试完整的Thunk执行流程:选方案1或3
- 如果你只需要隔离测试
functionToTest的调用逻辑:选方案2
内容的提问来源于stack exchange,提问作者Kevin
相关产品推荐
相关产品推荐

