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

如何为使用useAppDispatch与Redux Toolkit Slice的React自定义Hook编写测试?

解决自定义React Hook(Redux Toolkit + TypeScript)的Jest测试报错

问题分析

你的测试代码存在三个核心问题:

  • 错误尝试Spy独立导出的useAppDispatch函数,Jest无法通过这种方式mock函数模块
  • 未mock依赖的工具函数getStringToTheTemplate,导致测试依赖真实函数的行为
  • 不必要地Spy Redux Toolkit自动生成的action creator,违背RTK测试的最佳实践

修正后的测试代码

import { useFields } from "../ForgetPassword/data";
// Mock整个redux模块,包括useAppDispatch
jest.mock("../../app/redux", () => ({
  useAppDispatch: jest.fn(),
}));
// Mock工具函数getStringToTheTemplate
jest.mock("./utils", () => ({
  getStringToTheTemplate: jest.fn((value) => value), // 默认返回原值,可按需修改
}));
// 导入被mock后的模块
import { useAppDispatch } from "../../app/redux";
import { registrationFormSlice } from "../../entities/registration";
import { getStringToTheTemplate } from "./utils";

describe("useFields hook", () => {
  const dispatchMock = jest.fn();

  beforeEach(() => {
    // 给mock的useAppDispatch设置返回值
    (useAppDispatch as jest.Mock).mockReturnValue(dispatchMock);
    // 重置所有mock
    dispatchMock.mockReset();
    (getStringToTheTemplate as jest.Mock).mockReset();
  });

  it("should call dispatch with transformed value via setLastName action", () => {
    const getFields = useFields();
    const lastNameField = getFields()[0][0];
    const testValue = "Test";
    const transformedValue = "TransformedTest";
    
    // 手动指定工具函数的返回值,模拟转换行为
    (getStringToTheTemplate as jest.Mock).mockReturnValue(transformedValue);

    lastNameField.setValue(testValue);

    // 验证工具函数被调用
    expect(getStringToTheTemplate).toHaveBeenCalledWith(testValue);
    // 验证dispatch被调用,且参数是正确的action
    expect(dispatchMock).toHaveBeenCalledTimes(1);
    expect(dispatchMock).toHaveBeenCalledWith(
      registrationFormSlice.actions.setLastName(transformedValue)
    );
  });

  it("should return correct fields array structure", () => {
    const getFields = useFields();
    const fields = getFields();

    expect(fields).toEqual([
      [
        {
          label: "lastName",
          valueKey: "lastName",
          setValue: expect.any(Function),
        },
      ],
    ]);
    // 额外验证数组长度和字段类型
    expect(fields.length).toBe(1);
    expect(fields[0].length).toBe(1);
    expect(typeof fields[0][0].setValue).toBe("function");
  });
});

关键修改说明

  1. Mock整个模块而非Spy函数
    使用jest.mock("../../app/redux")来mock整个包含useAppDispatch的模块,完全控制该函数的返回值,避免Spy独立函数的无效操作。

  2. Mock工具函数getStringToTheTemplate
    通过jest.mock("./utils")mock工具函数,测试时可手动指定返回值,确保测试不依赖真实函数的转换逻辑,专注于Hook本身的行为。

  3. 验证Dispatch的Action而非Spy Action Creator
    RTK的action creator是纯函数,直接验证dispatch被调用的action内容(通过registrationFormSlice.actions.setLastName(transformedValue)生成的action对象),这是Redux测试的标准做法,比Spy action creator更可靠。

  4. TypeScript类型处理
    使用as jest.Mock断言mock后的函数类型,解决TypeScript的类型检查问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 17:54:59