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

React按钮点击调用Mock函数测试失败问题求助

问题:Mock函数testClick未被调用的原因及解决办法

我正在自学用react-testing library和Jest做React测试,始终搞不懂为什么Mock函数testClick没被调用。查了不少文章和视频但大多过时了,附上相关代码和测试失败结果,求指点。

Products.js组件代码

import React, { useState } from 'react';
import { fetchProducts } from '../service';

const Products = () => {
  const [product, setProduct] = useState('');

  const handleSubmit = (event) => {
    event.preventDefault();
    fetchProducts();
  };

  const hasBeenClicked = () => {
    console.log('clicked!');
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        <input
          type="text"
          value={product}
          onChange={(e) => setProduct(e.target.value)}
        />
      </label>
      <input
        type="submit"
        onClick={hasBeenClicked}
        data-testid="button"
        label="Search"
      />
    </form>
  );
};

export default Products;

Products.test.js测试代码

import React from 'react';
import { render, screen, cleanup, fireEvent } from '@testing-library/react';
import Products from './Products';


test('Button click triggers click event', () => {
  const testClick = jest.fn();
  const { getByTestId } = render(<Products click={testClick} />);
  const button = getByTestId('button');
  fireEvent.click(button);

  expect(testClick).toBeCalled();
});

测试失败结果

PASS  src/App.test.js
 FAIL  src/components/Products.test.js
  ● Console

    console.log
      clicked!

      at apply (src/components/Products.js:13:13)

  ● Button clicks triggers click event

    expect(jest.fn()).toBeCalled()

    Expected number of calls: >= 1
    Received number of calls:    0

      11 |   fireEvent.click(button);
      12 |
    > 13 |   expect(testClick).toBeCalled();
         |                     ^
      14 | });
      15 |

      at Object.<anonymous> (src/components/Products.test.js:13:21)

Test Suites: 1 failed, 1 passed, 2 total
Tests:       1 failed, 1 passed, 2 total
Snapshots:   0 total
Time:        3.18 s, estimated 4 s

问题原因与解决办法

核心原因

你的Products组件根本没有接收click这个props,按钮的onClick绑定的是组件内部定义的hasBeenClicked函数,和你在测试中传入的testClick完全没有关联,所以testClick自然不会被调用。

解决思路一:让组件接收点击回调props(推荐)

这种方式能提升组件的可复用性和可测试性,修改Products.js,让组件接收外部传入的点击回调:

import React, { useState } from 'react';
import { fetchProducts } from '../service';

// 接收onClick回调作为props
const Products = ({ onClick }) => {
  const [product, setProduct] = useState('');

  const handleSubmit = (event) => {
    event.preventDefault();
    fetchProducts();
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        <input
          type="text"
          value={product}
          onChange={(e) => setProduct(e.target.value)}
        />
      </label>
      <input
        type="submit"
        onClick={onClick} // 使用传入的外部回调
        data-testid="button"
        label="Search"
      />
    </form>
  );
};

export default Products;

然后修改测试代码里的组件传参,把click改成onClick:

test('Button click triggers click event', () => {
  const testClick = jest.fn();
  const { getByTestId } = render(<Products onClick={testClick} />);
  const button = getByTestId('button');
  fireEvent.click(button);

  expect(testClick).toBeCalled();
});

解决思路二:直接验证组件内部行为(适合不需要复用的场景)

如果不想修改组件结构,可以直接测试点击按钮后触发的内部逻辑,比如验证控制台输出或者submit事件对应的函数调用:

import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import Products from './Products';
import { fetchProducts } from '../service';

// Mock service里的fetchProducts函数
jest.mock('../service', () => ({
  fetchProducts: jest.fn()
}));

test('Button click triggers expected logic', () => {
  // 监听console.log
  const logSpy = jest.spyOn(console, 'log').mockImplementation();
  
  const { getByTestId } = render(<Products />);
  const button = getByTestId('button');
  fireEvent.click(button);

  // 验证console.log输出了'clicked!'
  expect(logSpy).toHaveBeenCalledWith('clicked!');
  // 验证submit事件触发了fetchProducts
  expect(fetchProducts).toHaveBeenCalled();

  // 恢复console.log的原始行为
  logSpy.mockRestore();
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 20:20:33