在Jest中监听React useReducer时Mock dispatch函数未触发问题排查
React useReducer 测试:Mock dispatch 未被调用的问题
我有一个采用useReducer模式的React应用,需要测试dispatch函数的输入值——直接断言组件内部状态既不简便也无意义,因此计划通过Mock React.useReducer,让它返回一个可用于断言的Mock dispatch函数。但目前遇到的问题是:Mock的dispatch函数从未被调用。
待测试组件代码
interface IState { name: string } interface IAction { type: "fetched data" | "manual update" newName: string } interface ITestComponentProps { name: string } const TestReducerComponent: React.FC<ITestComponentProps> = (props) => { const { name } = props; const initState = { name: name }; const handleUpdates = (state: IState, action: IAction): IState => { console.log("handle updates was called with " + action.newName); return { name: action.newName }; } // 原代码直接使用React.useReducer,这是Mock失效的核心原因 const [state, dispatch] = React.useReducer(handleUpdates, initState); React.useEffect(() => { // 关注dispatch的输入值 dispatch({ type: "fetched data", newName: "Max" }); }, []) return (<div></div>) } export default TestReducerComponent;
测试代码
import { render } from '@testing-library/react'; import TestReducerComponent from './TestReducerComponent'; import caller from './caller-Module'; it("react specific test", async () => { const mockedDispatcherFunction = jest.fn(); jest .spyOn(caller, 'useReducer') .mockImplementationOnce((reducer, initialState) => [initialState, mockedDispatcherFunction]); render(<TestReducerComponent name={"Peter"}></TestReducerComponent>) // 原断言参数错误:组件dispatch的是newName,而非initValues包裹的结构 expect(mockedDispatcherFunction).toHaveBeenCalledWith({ type: 'fetched data', initValues: { newName: "Max" } }); });
caller-Module 代码
import { useReducer } from "react"; const caller = { useReducer } export default caller;
问题原因与解决方案
核心问题
- Mock对象不匹配:组件中直接调用
React.useReducer,但测试里Mock的是caller.useReducer,两者不是同一个引用,导致Mock无法拦截组件内的useReducer调用。 - 断言参数错误:测试中的断言使用了
initValues: {newName: "Max"},但组件实际dispatch的是newName: "Max",参数结构不匹配。
修复步骤
修改组件的useReducer导入方式:
在组件中导入caller模块的useReducer,替换原有的React.useReducer:import caller from './caller-Module'; // ... const [state, dispatch] = caller.useReducer(handleUpdates, initState);修正测试中的断言参数:
将断言的参数改为组件实际dispatch的结构:expect(mockedDispatcherFunction).toHaveBeenCalledWith({ type: 'fetched data', newName: "Max" });修正组件名称拼写:
原组件定义为TestRedcuerComponent(少了字母d),测试中使用TestReducerComponent,需统一名称避免渲染错误。
内容的提问来源于stack exchange,提问作者Feuerschinken
相关产品推荐
相关产品推荐

