Jest测试时mock函数调用次数始终为0怎么办?

UX-云碧 阅读 26

在测试React组件时遇到了奇怪的问题。我用jest.fn()模拟了一个handleClick函数,但测试时expect(mockFn.mock.calls.length).toBe(1)一直报错说实际是0。组件里确实绑定了这个函数,测试代码也用了fireEvent.click…

我已经尝试过在测试最后加了waitFor(),也确认过事件绑定没有错。但控制台打印mockFn的calls数组始终是空的。这是不是和React的StrictMode有关?或者是不是应该用useEffect来手动触发?

组件代码:

const MyButton = ({ onClick }) => {
  return <button onClick={() => onClick('test')}>Click me</button>;
};

测试代码报错部分:

test('should call handleClick', async () => {
  const mockFn = jest.fn();
  render(<MyButton onClick={mockFn} />);
  fireEvent.click(screen.getByText('Click me'));
  await waitFor(() => expect(mockFn).toHaveBeenCalled());
});

我来解答 赞 2 收藏
二维码
手机扫码查看
2 条解答
シ广红
シ广红 Lv1
这个问题大概率是React的StrictMode导致的,它在开发环境下会触发组件的双重渲染。你提到的mock函数调用次数为0,很可能是因为在第二次渲染时,事件处理器被重新绑定,但测试框架只触发了第一次渲染的点击事件。

按照官方文档的说法,StrictMode会在开发模式下故意触发两次渲染,目的是帮助开发者发现潜在的副作用问题。不过这确实会给测试带来一些麻烦。

解决方法其实很简单,标准写法是在测试环境中禁用StrictMode。如果你用的是create-react-app,可以在 src/setupTests.js 里加一行代码:

import { configure } from '@testing-library/react';
configure({ strict: false });


或者更推荐的做法是直接修改测试用例,确保事件绑定正确:

test('should call handleClick', () => {
const mockFn = jest.fn();
render(<MyButton onClick={mockFn} />);

// 获取按钮元素
const button = screen.getByText('Click me');

// 确保事件绑定无误
expect(button).toBeInTheDocument();

// 触发点击事件
fireEvent.click(button);

// 验证调用情况
expect(mockFn).toHaveBeenCalledTimes(1);
expect(mockFn).toHaveBeenCalledWith('test');
});


这里有几个关键点:第一,不需要用 async/awaitwaitFor,因为事件触发是同步的;第二,要验证参数传递是否正确;第三,确保测试环境和实际运行环境一致。

说实话,React的这个行为确实让人头疼,特别是对新手来说。我之前也被坑过好几次,后来严格按照官方文档的最佳实践来写测试,类似的问题就少了很多。记得多看看React Testing Library的文档,他们对这些常见问题都有详细的说明。
点赞
2026-02-15 16:03
柯佳~
柯佳~ Lv1
你这个问题是fireEvent同步触发但没等回调执行完就去检查了。把await waitFor去掉,或者直接用act包一层就行。

test('should call handleClick', () => {
const mockFn = jest.fn();
render();
fireEvent.click(screen.getByText('Click me'));
expect(mockFn).toHaveBeenCalledTimes(1);
});
点赞 4
2026-02-12 23:05