父作用域已Mock函数,如何在特定Jest测试中重新Mock?
问题
我已经在父作用域中通过以下代码Mock了../../hooks/any-hook中的useCreateMutation:
jest.mock('../../hooks/any-hook', () => ({ useCreateMutation: () => ({ mutate: jest.fn(), isLoading: false, isSuccess: false, }) }));
现在想在特定测试用例中重新Mock该函数并修改返回值,但使用jest.doMock没有生效,该怎么解决?
解决方法
由于jest.mock会被Jest预编译时自动提升到代码顶部执行,直接用jest.doMock无法覆盖全局Mock,推荐以下两种可行方案:
方案一:直接修改已Mock函数的实现
这种方式无需重新Mock整个模块,直接修改现有Mock的返回值即可,是最常用的方案:
- 先在测试文件顶部导入被Mock的hook:
import { useCreateMutation } from '../../hooks/any-hook';
- 在目标测试用例中,替换
useCreateMutation的Mock实现:
test('特定测试用例:修改useCreateMutation返回值', () => { // 替换为自定义的返回值 (useCreateMutation as jest.Mock).mockReturnValue({ mutate: jest.fn().mockResolvedValue({ id: 123 }), isLoading: true, isSuccess: false, }); // 执行你的测试逻辑(比如渲染组件、触发操作等) });
如果需要在测试后恢复初始Mock,可以在afterEach钩子中重置:
afterEach(() => { jest.clearAllMocks(); // 恢复到父作用域的初始Mock实现 (useCreateMutation as jest.Mock).mockReturnValue({ mutate: jest.fn(), isLoading: false, isSuccess: false, }); });
方案二:用jest.isolateModules隔离模块加载
如果必须重新Mock整个模块,可通过jest.isolateModules创建隔离的模块加载环境,确保新Mock生效:
test('特定测试用例:重新Mock整个模块', () => { jest.isolateModules(() => { // 在隔离环境中重新定义Mock jest.mock('../../hooks/any-hook', () => ({ useCreateMutation: () => ({ mutate: jest.fn().mockRejectedValue(new Error('创建失败')), isLoading: false, isSuccess: false, }) })); // 必须在Mock之后动态导入组件和hook const { useCreateMutation } = require('../../hooks/any-hook'); const YourComponent = require('../YourComponent').default; // 执行测试逻辑 }); });
为什么jest.doMock不生效?
jest.mock会被Jest预编译时提升到文件最顶部,而jest.doMock不会自动提升。如果你在导入组件或hook之后调用jest.doMock,此时模块已经加载了旧的Mock,自然不会生效。若一定要用jest.doMock,必须确保它在所有模块导入前执行,配合动态require使用,但这种方式复杂度更高,不推荐。
内容的提问来源于stack exchange,提问作者Ahmad Ali
相关产品推荐
相关产品推荐

