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

如何用Vitest模拟useState钩子并验证setState是否被调用?

在Vitest中正确测试React组件调用setState的方法

我正把React应用的测试框架从Jest迁移到Vitest,需要测试某个组件在特定场景下是否调用setState函数。此前Jest的实现代码如下:

it('Component should call setState on render', () => {
    const setState = jest.fn();

    jest.spyOn(React, 'useState').mockReturnValue(['', setState]);

    render(<Component />);

    expect(setState).toHaveBeenCalledWith('text');
});

但将jest.替换为vi.后测试失败,报错信息如下:

FAIL  src/__tests__/components/Component.spec.tsx > Component > Component should call setState on render
AssertionError: expected "spy" to be called with arguments: [ 'text' ]expected "spy" to be called with arguments: [ 'text' ]

Received:


Number of calls: 0

 ❯ src/__tests__/components/Component.spec.tsx:82:19
     80|   );
     81|
     82|   expect(setState).toHaveBeenCalledWith('text');
       |                   ^
     83|  });
     84|

解决方法

直接替换jest为vi后测试失败,核心原因是Vitest对React内置Hook的模拟细节与Jest有差异,调整以下几点即可修复:

  1. 确保Mock时机与清理:在测试前完成useState的Mock,测试后恢复原始实现避免污染其他测试;
  2. 使用正确的Mock方式:优先用vi.spyOn配合mockReturnValue或mockImplementation,确保模拟的useState返回预期的初始值和mock函数。

修正后的测试代码:

// 可选:在所有测试后自动恢复mock,避免残留影响
afterEach(() => {
  vi.restoreAllMocks();
});

it('Component should call setState on render', () => {
  // 创建mock的setState函数
  const setState = vi.fn();
  // 模拟React.useState,返回初始空字符串和mock函数
  vi.spyOn(React, 'useState').mockReturnValue(['', setState]);

  // 渲染组件
  render(<Component />);

  // 断言setState被正确调用
  expect(setState).toHaveBeenCalledWith('text');
});

额外注意事项

  • 确认你的组件确实会在挂载/渲染阶段调用setState('text')(比如在useEffect中触发,而非直接在render函数内调用,否则会引发无限循环);
  • 如果使用React 18,确保测试环境已适配(比如@testing-library/react版本≥13),避免render行为差异导致的mock捕获失败;
  • 若上述方法仍不生效,可以尝试用mockImplementation替代mockReturnValue,效果一致但兼容性更好:
    vi.spyOn(React, 'useState').mockImplementation(() => ['', setState]);
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 19:10:47