如何在TypeScript中用Jest mockImplementation模拟自定义Hook实现组件单元测试
React自定义Hook单元测试模拟方案
现有写法问题
你当前的jest.mock写法不符合Hook的调用逻辑:useAPICall本身是可执行的函数,你直接返回了包含onAPICall的对象,执行useAPICall(123)时会因为返回值不是可调用函数报错。
正确模拟方式
1. 全局基础模拟
首先在测试文件顶层编写全局模拟逻辑,完全替换原Hook的实现:
jest.mock('@src/hooks/useAPICall', () => { // 返回模拟的useAPICall函数,执行后返回Hook的模拟返回值 return jest.fn(() => ({ onAPICall: jest.fn() })) })
该写法会完全屏蔽原Hook的所有逻辑,测试时不会执行原Hook的任何代码,符合你的需求。
2. 测试用例编写示例
以React Testing Library为例,完整测试代码如下:
import { render, screen, fireEvent } from '@testing-library/react' import App from './App' import useAPICall from '@src/hooks/useAPICall' // 类型声明(TS环境可选,用于获取模拟函数的类型提示) const mockUseAPICall = useAPICall as jest.Mock describe('App组件测试', () => { // 每个用例执行前清空模拟函数的调用记录,避免用例间相互干扰 beforeEach(() => { mockUseAPICall.mockClear() }) it('点击按钮时触发onAPICall调用', () => { // 自定义本次Hook调用的返回值,方便后续断言 const mockOnAPICall = jest.fn() mockUseAPICall.mockReturnValue({ onAPICall: mockOnAPICall }) render(<App />) // 触发按钮点击 fireEvent.click(screen.getByRole('button', { name: /click/i })) // 断言逻辑 expect(mockUseAPICall).toHaveBeenCalledWith(123) // 验证Hook传入参数正确 expect(mockOnAPICall).toHaveBeenCalledTimes(1) // 验证接口调用方法被触发 }) })
3. 无返回值Hook的模拟说明
如果你的自定义Hook没有返回值,只需要修改mockImplementation的返回逻辑即可:
// 模拟无返回值的自定义Hook mockUseAPICall.mockImplementation(() => { // 不需要返回任何内容 // 也可以在这里添加模拟的副作用逻辑 })
注意事项
jest.mock必须写在测试文件的顶层,不能放在测试用例内部,jest会自动提升该方法的执行优先级,早于所有import语句执行- 不同测试用例需要不同Hook返回值时,直接在对应用例内调用
mockReturnValue/mockImplementation覆盖即可
内容的提问来源于stack exchange,提问作者jacobcan118
相关产品推荐
相关产品推荐

