You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jest测试React组件:验证Mock自定义Hook返回函数的调用

无侵入Mock Hook并验证返回函数调用的实现方案

你不需要修改组件Props做依赖注入,直接在jest.mock的模块mock实现中挂载可追踪的mock函数,即可在测试用例中直接断言调用状态,全程不需要改动业务组件代码。

核心实现要点

  • 先在测试文件的顶层作用域声明命名以mock开头的mock函数,Jest会自动在每个测试用例跑完后重置这类函数的调用记录,不会出现用例之间状态污染的问题
  • 调用jest.mock时传入第二个参数作为模块工厂函数,把自定义Hook的默认导出实现为返回包含mock函数的对象
  • 渲染组件后直接对提前声明的mock函数做断言即可;因为useEffect是在组件渲染完成后才执行的,建议用waitFor包裹断言,避免因为执行时序问题报假错

完整代码示例

测试文件代码

import { render, waitFor } from '@testing-library/react';
import MyComponent from '@/components/MyComponent';
// 提前声明可追踪的mock函数,注意命名以mock开头
const mockSetQuery = jest.fn();

// 直接mock对应Hook模块,传入自定义实现
jest.mock('@/hooks/useAutocomplete', () => ({
  // 适配ES模块默认导入规则,避免导入报错
  __esModule: true,
  default: () => ({
    setQuery: mockSetQuery
  })
}));

it("组件挂载时会用空对象调用setQuery", async () => {
  render(<MyComponent />);
  
  // 等待useEffect逻辑执行完成
  await waitFor(() => {
    // 验证调用次数,两种写法等价
    expect(mockSetQuery).toHaveBeenCalledTimes(1);
    // expect(mockSetQuery.mock.calls.length).toBe(1);

    // 验证入参符合预期,两种写法等价
    expect(mockSetQuery).toHaveBeenCalledWith({});
    // expect(mockSetQuery.mock.calls[0][0]).toEqual({});
  })
})

注意:如果你在Jest配置中开启了resetMocks: true,需要在beforeEach钩子中重新给mock函数赋值实现,或者把配置项调整为clearMocks: true——后者只会清空调用记录,不会清空mock函数的实现,更适合当前场景。

初始写法无法生效的原因

你之前只调用了jest.mock("@/hooks/useAutocomplete"),Jest只会自动把模块导出的Hook本身替换为自动生成的mock函数,但Hook内部返回的setQuery是一个普通空函数,没有被替换为可追踪的jest.fn()实例,自然拿不到调用记录。

这个方案完全不需要修改业务组件的入参定义,没有侵入性,是Jest mock模块场景下的标准写法。

内容的提问来源于stack exchange,提问作者kapantzak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 22:18:13