如何在Jest中Mock第三方库的自定义Hook?
正确Mock第三方库自定义Hook的Jest方案
你遇到的问题核心是Mock时机不对,以及Mock方式不符合Jest的模块加载机制,以下是解决方法:
关键问题分析
- 方式一的问题:
jest.mock不能放在it测试用例内部。Jest的模块Mock会被提升到文件顶部优先执行,如果在测试用例里才声明Mock,组件早就已经导入并使用了原始的Hook,Mock自然不会生效。 - 方式二的问题:如果只是返回普通函数而非
jest.fn(),不仅无法动态修改返回值,同样可能因为Mock时机晚于组件导入,导致使用原始Hook。
正确实现步骤
1. 顶层声明Mock(必做)
把jest.mock放在测试文件的最顶部(所有import和测试用例之前),确保组件在导入时就使用Mock后的模块:
// 顶层Mock,优先于所有模块执行 jest.mock('@third/prod-data-component', () => ({ // 将Hook定义为jest mock函数,方便后续动态修改返回值 useProductData: jest.fn() })); // 必须在Mock之后导入组件和相关依赖 import ProductRow from './ProductRow'; import { render, screen } from '@testing-library/react'; // 导入Mock后的Hook,用于设置返回值 import { useProductData } from '@third/prod-data-component';
2. 在测试用例中动态设置返回值
在每个测试用例里,通过mockReturnValue或mockReturnValueOnce设置Hook的返回值:
it('渲染正确的产品数据', () => { // 给Mock的Hook设置返回值 useProductData.mockReturnValue('foo'); render(<ProductRow />); // 断言数据是否正确渲染 expect(screen.getByText('foo')).toBeInTheDocument(); }); it('处理产品数据为undefined的情况', () => { // 另一个测试用例可以设置不同的返回值 useProductData.mockReturnValue(undefined); render(<ProductRow />); // 断言无数据时的渲染结果 expect(screen.queryByText('foo')).not.toBeInTheDocument(); });
3. 保留库中其他导出的真实实现(可选)
如果需要保留第三方库中其他导出的真实功能,仅MockuseProductData,可以这样写:
jest.mock('@third/prod-data-component', () => { // 获取库的真实实现 const actualLib = jest.requireActual('@third/prod-data-component'); return { // 保留其他所有导出 ...actualLib, // 仅Mock目标Hook useProductData: jest.fn() }; });
注意事项
- 必须确保组件的
import语句在jest.mock之后,ES模块的静态导入会优先执行,提前导入组件会导致使用原始模块。 - 每次测试用例执行后,可以用
useProductData.mockClear()清除Mock的调用记录,避免测试用例之间的污染。
内容的提问来源于stack exchange,提问作者user842225
相关产品推荐
相关产品推荐

