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

Jest如何测试React函数式组件内部的函数与关联状态?

React函数组件的内部状态和自定义内部函数不属于公共实例属性,Enzyme的state()、invoke()等针对类组件设计的API无法直接调用获取对应内容。以下是两种无需触发DOM事件即可完成测试的方案:

方案1:抽离自定义Hook单独测试(推荐)

将状态逻辑抽为独立自定义Hook,无需挂载整个组件即可直接测试逻辑正确性:

// 抽离的独立Hook
import { useState } from 'react';

export const useMenuToggle = (initialState = false) => {
  const [openMenu, setOpenMenu] = useState(initialState);
  const toggleMenu = () => setOpenMenu(prev => !prev);
  return { openMenu, toggleMenu };
};

调整原有组件引入Hook:

const Component: React.FC = () => {
  const { openMenu, toggleMenu } = useMenuToggle(false);

  return (
    <div>
      <ChildComponent openMenu={openMenu} toggleMenu={toggleMenu} />
    </div>
  );
};

export default Component;

使用@testing-library/react的renderHook编写测试:

import { renderHook, act } from '@testing-library/react';
import { useMenuToggle } from './useMenuToggle';

test('should toggle openMenu state correctly', () => {
  const { result } = renderHook(() => useMenuToggle(false));
  // 校验初始状态
  expect(result.current.openMenu).toBe(false);
  // 调用toggleMenu更新状态
  act(() => {
    result.current.toggleMenu();
  });
  expect(result.current.openMenu).toBe(true);
  // 校验二次切换逻辑
  act(() => {
    result.current.toggleMenu();
  });
  expect(result.current.openMenu).toBe(false);
});

方案2:直接读取子组件Props操作(无需修改业务代码)

如果不需要调整原有组件代码,可以直接从组件树中读取传给ChildComponent的props,获取toggleMenu函数直接调用:

Enzyme版本测试代码

test('should be able to toggle open menu state', () => {
  const wrapper = shallow(
    <Provider store={store}>
      <MemoryRouter initialEntries={['/']}>
        <DefaultLayout />
      </MemoryRouter>
    </Provider>
  );
  // 找到子组件获取传入的props
  const childComponent = wrapper.find(ChildComponent);
  // 校验初始状态
  expect(childComponent.prop('openMenu')).toBe(false);
  // 直接调用toggleMenu
  childComponent.prop('toggleMenu')();
  // 校验更新后状态
  expect(childComponent.prop('openMenu')).toBe(true);
});

React Testing Library版本测试代码

// 先mock子组件
jest.mock('./ChildComponent', () => ({
  __esModule: true,
  default: jest.fn(() => null)
}));

test('should toggle openMenu correctly', () => {
  render(
    <Provider store={store}>
      <MemoryRouter initialEntries={['/']}>
        <DefaultLayout />
      </MemoryRouter>
    </Provider>
  );
  // 读取传给子组件的初始props
  const [initialProps] = ChildComponent.mock.calls[0];
  expect(initialProps.openMenu).toBe(false);
  // 调用toggleMenu
  initialProps.toggleMenu();
  // 读取更新后的props校验
  const [updatedProps] = ChildComponent.mock.calls[1];
  expect(updatedProps.openMenu).toBe(true);
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 14:57:01