自定义hook的单元测试

138 阅读1分钟

法一

Testing Library 提供的一个专门的 React Hooks 测试包:@testinglibrary/react-hooks。使用它的方式如下面代码所示:

import { renderHook, act } from '@testing-library / react - hooks';
import useCounter from './useCounter';
test('useCounter3', () => {
  //    使用renderHook API  来调用一个 Hook
  const { result } = renderHook(() => useCounter());
  //    Hook  的返回值会存储在  result.current  中
  //  调用加一方法
  act(() => { result.current.increment(); });
  //  验证结果为  1
  expect(result.current.count).toBe(1);
});

法二

一个思路上比较直观的做法就是创建一个测试组件,在这个测试组件内部使用这个Hook。因此对于 Hook 的测试,就可以转换为对组件的测试。

但是呢,这样做的缺点也是显而易见的:我们需要写很多与 Hooks 测试本身无关的代码。比如多余的 DOM 元素。

我们能否更直接地操作 Hooks 的 API 呢?其实也是可以的。我们可以将useCounter 这个 Hook 的返回值暴露到函数组件之外,然后由测试代码直接调用这些API 并验证结果。下面的代码就演示了这种做法:

import { render, act } from '@testing-library / react';
import useCounter from './useCounter';
test('useCounter', () => {
  const hookResult = {};
  //    创建一个测试组件,仅运行 Hook,不产生任何UI
  const WrapperComponent = () => {
    //将 useCounter的返回值复制给外部的hookResult对象
    Object.assign(hookResult, useCounter());
    return null;
  };
  //    渲染测试组件
  render(<WrapperComponent />);
  //    调用hook的increment方法
  act(() => { hookResult.increment(); });
  //    验证结果为    1
  expect(hookResult.count).toBe(1);

});

来源:《React Hooks 核心原理与实战》--王沛