如何在Jest中模拟另一个Hook内部调用的自定义Hook?
解决自定义Hook测试中mock内部Hook不生效的问题
问题根源
你的mock没生效主要有两个原因:
jest.mock的位置错误:它写在了renderHook之后,而renderHook在describe顶层执行时,useCopySystem已经导入并使用了原有的useBackdrop,mock 没来得及生效。renderHook放在了describe顶层:describe块内的代码会在所有测试用例执行前运行,此时mock还未正确应用,导致hook使用了未被mock的依赖。
修复步骤
- 将
jest.mock移到模块最顶部:jest.mock会被 Jest 自动提升到模块作用域的最顶端,确保在导入useCopySystem之前就完成mock。 - 把
renderHook移到测试用例(it)内部:确保每次测试时,hook都是在mock生效后才被渲染。 - 确保mock的返回值符合预期:根据你的需求,让
showBackdrop返回true。
修正后的代码示例
// 把mock放在模块最顶部,确保在导入useCopySystem前执行 jest.mock('../utilities/useBackdrop', () => ({ __esModule: true, useBackdrop: jest.fn(() => ({ showBackdrop: jest.fn(() => true), })), })); import { renderHook } from '@testing-library/react'; import { Provider } from 'react-redux'; import configureStore from '@reduxjs/toolkit/configureStore'; import authReducer from '../path-to-auth-reducer'; import globalReducer from '../path-to-global-reducer'; import miscReducer from '../path-to-misc-reducer'; import useCopySystem from '../path-to-useCopySystem'; const createTestStore = () => configureStore({ reducer: { auth: authReducer, global: globalReducer, misc: miscReducer, }, }); // Wrapper const wrapper = ({ children }) => <Provider store={createTestStore()}>{children}</Provider>; describe('test copy system', () => { it('pasteCopiedDay', async () => { // 在测试用例内部渲染hook,确保mock已生效 const { result } = renderHook(() => useCopySystem(), { wrapper }); const { pasteCopiedDay } = result.current; await pasteCopiedDay('day3Id', mockedCopyDayType); // 可选:添加断言验证mock是否被正确调用 const { useBackdrop } = require('../utilities/useBackdrop'); expect(useBackdrop).toHaveBeenCalled(); expect(useBackdrop().showBackdrop).toHaveBeenCalled(); }); });
额外注意点
- 如果需要在不同测试用例中mock不同的返回值,可以在
it块内使用jest.mocked(useBackdrop).mockReturnValue(...)来动态修改mock返回值。 - 确保
wrapper中的store是每次测试都重新创建的,避免测试之间的状态污染(上面的代码已经把createTestStore()放在了wrapper内部,每次渲染都会生成新store)。
内容的提问来源于stack exchange,提问作者Richardson
相关产品推荐
相关产品推荐

