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

如何为React中useEffect钩子内的if条件语句编写单元测试用例

useEffect条件分支测试实现方案

我们使用React Testing Library + Jest 完成测试,核心逻辑是mock redux的useSelector、useDispatch两个钩子,分别覆盖if条件成立、不成立两种场景。

测试前置准备

先完成依赖mock和基础引入:

import { render } from '@testing-library/react';
import { useDispatch, useSelector } from 'react-redux';
import Greet from './Greet';
// 替换为你实际存放getDetails action的文件路径
import { getDetails } from '@/store/actions';

// 全局mock react-redux提供的钩子
jest.mock('react-redux', () => ({
  useDispatch: jest.fn(),
  useSelector: jest.fn(),
}));
// 模拟getDetails action,避免触发真实接口请求
jest.mock('@/store/actions', () => ({
  getDetails: jest.fn(),
}));

测试用例1:命中if条件(两个数组都为空)

验证组件挂载后会调用dispatch(getDetails()):

test('state和country数据都为空时,触发getDetails dispatch', () => {
  const mockDispatch = jest.fn();
  useDispatch.mockReturnValue(mockDispatch);
  // 模拟redux返回两个空数组,命中判断条件
  useSelector.mockImplementation((selector) => 
    selector({
      stateDatalist: [],
      CountryDatalist: []
    })
  );

  render(<Greet />);

  // 断言dispatch调用符合预期
  expect(mockDispatch).toHaveBeenCalledWith(getDetails());
  expect(getDetails).toHaveBeenCalledTimes(1);
});

测试用例2:不命中if条件(至少一个数组不为空)

验证组件挂载后不会触发对应dispatch:

test('任一数据不为空时,不触发getDetails dispatch', () => {
  const mockDispatch = jest.fn();
  useDispatch.mockReturnValue(mockDispatch);
  // 模拟stateDatalist有值,不命中判断条件
  useSelector.mockImplementation((selector) => 
    selector({
      stateDatalist: [{ id: 1, name: '广东省' }],
      CountryDatalist: []
    })
  );

  render(<Greet />);

  // 断言dispatch未触发
  expect(mockDispatch).not.toHaveBeenCalledWith(getDetails());
  expect(getDetails).toHaveBeenCalledTimes(0);
});

补充说明

你当前组件的useEffect依赖是空数组,只会在组件首次挂载时执行一次,无需额外测试更新场景;如果后续调整了useEffect的依赖项,需要对应补充依赖变更后的测试逻辑。如果getDetails是异步thunk类型的action,上述测试逻辑依然适用,无需调整。

内容的提问来源于stack exchange,提问作者Pavan Kalyan Payyavula

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 01:30:01