React单元测试中如何监视useNavigate?遇重定义错误求解决
问题原因
react-router-dom 导出的 useNavigate 是一个不可配置的属性(内部用 Object.defineProperty 定义时设置了 configurable: false),而 jest.spyOn 的工作原理是尝试重新定义这个属性来替换成 mock 函数,由于属性不可配置,所以会抛出 Cannot redefine property 的错误。
解决方案
不要用 jest.spyOn,直接通过 jest.mock 来模拟 useNavigate,同时保留 react-router-dom 的其他原有功能:
import { useNavigate } from 'react-router-dom'; // 模拟react-router-dom,只替换useNavigate为mock函数 jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), // 继承原模块的其他导出 useNavigate: jest.fn(), }));
完整测试示例
假设你要测试的组件包含一个点击后跳转的按钮,测试代码可以这样写:
import { render, screen, fireEvent } from '@testing-library/react'; import { useNavigate } from 'react-router-dom'; import TargetComponent from './TargetComponent'; jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), useNavigate: jest.fn(), })); test('点击按钮后正确调用useNavigate并传入目标路径', () => { // 渲染组件 render(<TargetComponent />); // 触发按钮点击 fireEvent.click(screen.getByRole('button', { name: '跳转' })); // 验证调用次数和参数 expect(useNavigate).toHaveBeenCalledTimes(1); expect(useNavigate).toHaveBeenCalledWith('/expected-path'); });
注意事项
- 必须使用
...jest.requireActual('react-router-dom'),否则其他如useParams、Link等react-router-dom的功能会被完全模拟,导致测试时无法正常使用。 - 如果你的测试不需要其他
react-router-dom的功能,也可以直接模拟整个模块而不继承原有导出,但这种场景较少。
内容的提问来源于stack exchange,提问作者ptjr
相关产品推荐
相关产品推荐

