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

测试mock useState时是否也需要对useEffect进行mock?

错误根本原因

你当前的实现全局劫持了所有React.useState的调用,所有用到useState的位置(包括组件内其他useState、React 内部Hook逻辑、依赖useState的自定义Hook)都会返回同一个模拟的setState函数,直接破坏了React Hook的调用顺序规则,同时导致依赖该useState返回值的useEffect拿到了不符合预期的输入,才会触发length读取失败、Hook调用顺序异常的报错。

是否需要mock useEffect

不需要专门mock useEffect,你的问题本质是测试思路不合理:测试组件行为不应该通过mock底层Hook的方式验证内部实现细节,应该直接验证组件对外的表现是否符合预期。

推荐解决方案

方案1:改为测试组件实际表现(优先选择)

不要验证setState的调用情况,直接测试鼠标事件触发后组件的渲染结果是否符合预期,比如悬浮对应的提示是否展示、对应样式类是否生效等,示例代码如下:

test('should toggle hover state on mouse enter and leave', () => {
  // 假设悬浮时会展示类名为hover-tooltip的提示元素
  expect(screen.queryByClassName('hover-tooltip')).not.toBeInTheDocument()

  fireEvent.mouseEnter(point)
  expect(screen.getByClassName('hover-tooltip')).toBeInTheDocument()

  fireEvent.mouseLeave(point)
  expect(screen.queryByClassName('hover-tooltip')).not.toBeInTheDocument()
})

这种测试更稳定,不会因为组件内部state的实现逻辑调整就失效。

方案2:仅mock目标useState调用(不推荐)

如果确实需要验证setState的调用情况,不要全局mock所有useState,仅针对你要测试的那一次useState调用做模拟,其余useState保留原生实现:

test('should update state on mouse enter and mouse leave', () => {
  const setStateMock = jest.fn()
  const originUseState = React.useState
  let useStateCallTimes = 0
  // 假设你要测试的useState是组件内第3个调用的Hook,对应调用次数为3时返回mock值
  const TARGET_USESTATE_INDEX = 3

  jest.spyOn(React, 'useState').mockImplementation((initValue) => {
    useStateCallTimes++
    if (useStateCallTimes === TARGET_USESTATE_INDEX) {
      return [initValue, setStateMock]
    }
    return originUseState(initValue)
  })

  point.simulate('mouseenter')
  expect(setStateMock).toBeCalledTimes(1)
  expect(setStateMock).toHaveBeenCalledWith(true)

  point.simulate('mouseleave')
  expect(setStateMock).toBeCalledTimes(2)
  expect(setStateMock).toHaveBeenCalledWith(false)

  // 测试完成后恢复原生实现
  jest.restoreAllMocks()
})

注意这种写法非常脆弱,只要组件内的Hook调用顺序发生变化(比如在目标useState之前新增了其他Hook),测试就会直接失效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.14 21:06:01