pro-collection / interview-question

目标:收集全网经典面试问题
536 stars 37 forks source link

[React] 如何针对 react hooks 写单测【热度: 170】 #775

Open yanlele opened 3 months ago

yanlele commented 3 months ago

关键词:hooks 单测

如果你想对一个独立的 React Hook 函数进行单元测试,不涉及对它在组件中使用的测试,那么你可以使用由react-hooks-testing-library提供的工具来完成。这个库允许你在一个隔离的环境中渲染和测试 hook 函数,而不必担心组件的其他部分。

首先,你需要安装@testing-library/react-hooks

npm install --save-dev @testing-library/react-hooks

或者使用 yarn:

yarn add --dev @testing-library/react-hooks

然后,让我们以一个简单的useCounter Hook 为例,来看怎么进行单元测试。以下是这个 Hook 的代码:

import { useState, useCallback } from "react";

function useCounter(initialValue = 0) {
  const [count, setCount] = useState(initialValue);
  const increment = useCallback(() => setCount((c) => c + 1), []);
  const decrement = useCallback(() => setCount((c) => c - 1), []);

  return { count, increment, decrement };
}

export default useCounter;

接下来是对应的单元测试:

import { renderHook, act } from "@testing-library/react-hooks";
import useCounter from "./useCounter";

describe("useCounter", () => {
  it("should use counter", () => {
    const { result } = renderHook(() => useCounter());

    expect(result.current.count).toBe(0);
  });

  it("should increment counter", () => {
    const { result } = renderHook(() => useCounter());

    act(() => {
      result.current.increment();
    });

    expect(result.current.count).toBe(1);
  });

  it("should decrement counter", () => {
    const { result } = renderHook(() => useCounter(10));

    act(() => {
      result.current.decrement();
    });

    expect(result.current.count).toBe(9);
  });
});

这里我们使用了renderHook函数来渲染我们的 hook 并返回一个对象,这个对象中包含当前 hook 返回的所有值。我们还使用了act函数来包裹我们对 hook 中函数的调用。这是因为 React 需要确保在测试过程中状态更新能够正常同步。

需要注意的是,如果你的 hook 依赖于其他 React 的 Context,你可以使用renderHook的第二个参数来传入一个 wrapper,该 wrapper 是一个 React 组件,它将包裹你的 hook。

上面的这个测试覆盖了 hook 在默认值和指定初始值时的行为,以及它暴露的incrementdecrement函数是否正常工作。这种方式可以用来测试任何自定义 hook,并且只关注 hook 本身的逻辑,不涉及到任何组件。