1、使用 Jest 创建单元测试

  1. <br />主要需要了解以下三点:
  1. Jest 从哪里寻找测试文件;
  2. 如何创建一个测试用例,并用断言验证测试结果;
  3. 如何运行测试。 ```jsx export default (a, b) => a + b;

import add from ‘./add’;

// 通过 test 函数创建一个测试用例 test(‘renders learn react link’, () => { // 执行 add 函数得到结果 const s = add(1, 2); // 使用 Jest 提供的 expect 函数断言结果等于3 expect(s).toBe(3); })

  1. 运行结果:<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1191101/1639018985210-d2cb496f-e49e-4a81-9f05-29626f903eab.png#clientId=uccd7f0db-303d-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=628&id=u80250fba&margin=%5Bobject%20Object%5D&name=image.png&originHeight=628&originWidth=1544&originalType=binary&ratio=1&rotation=0&showTitle=false&size=338073&status=done&style=none&taskId=uf1b8d86f-bdc0-4082-8cae-dde2c281b34&title=&width=1544)
  2. <a name="VHFnY"></a>
  3. # 2、使用 React Testing Library 测试 React 组件
  4. ```jsx
  5. // 引入 testing-library 提供的相关工具
  6. import { render, screen } from '@testing-library/react';
  7. // 引入要测试的组件
  8. import App from './App';
  9. // 创建一个测试用例
  10. test('renders learn react link', () => {
  11. // 使用 render 方法渲染 App 组件
  12. render(<App />);
  13. // 通过 screen 提供的 getByText 找到页面上的 DOM 元素
  14. const linkElement = screen.getByText(/learn react/i);
  15. // 断言这个元素应该在页面上
  16. expect(linkElement).toBeInTheDocument();
  17. });

Testing Library 提供的三个 React 相关的测试 API:

  1. render:用于在内存中 render 一个 React 组件。
  2. screen:提供了工具方法,用于获取屏幕上的元素。比如这里的 screen.getByText,就 是用来根据文本获取 DOM 元素的。
  3. expect 扩展:Testing Library 扩展了 expect 的功能,以方便对 UI 元素进行断言判 断。比如例子中的 toBeInTheDocument ,就是用于断言 DOM 元素需要存在于 Document 中。

3、如何对自定义 Hooks 进行单元测试

  1. <br />**创建一个测试组件**,**在这个测试组件内部使用这个 Hook**。
  1. import { render, fireEvent, screen } from '@testing-library/react'; import useCounter from './useCounter';
  2. test('useCounter', () => {
  3. // 创建一个测试组件,使用 useCounter 的所有逻辑
  4. const WrapperComponent = () => {
  5. const { count, increment, decrement } = useCounter();
  6. return (
  7. <>
  8. <button id="btnMinus" onClick={decrement}>-</button>
  9. <span id="result">{count}</span>
  10. <button id="btnAdd" onClick={increment}>+</button>
  11. </>
  12. );
  13. };
  14. // 渲染这个测试组件
  15. render(<WrapperComponent />);
  16. // 找到页面的三个 DOM 元素用于执行操作以及验证结果
  17. const btnAdd = document.querySelector('#btnAdd');
  18. const btnMinus = document.querySelector('#btnMinus');
  19. const result = document.querySelector('#result');
  20. // 模拟点击加一按钮
  21. fireEvent.click(btnAdd);
  22. // 验证结果是不是 1
  23. expect(result).toHaveTextContent('1');
  24. // 模拟点击减一按钮
  25. fireEvent.click(btnMinus);
  26. // 验证结果是不是 0
  27. expect(result).toHaveTextContent('0');
  28. }

这样做的缺点是我们需要写很多与 Hooks 测试本身无关的代码。 比如页面上的这些 DOM 元素。

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

  1. import { render, act } from '@testing-library/react';
  2. import useCounter from './useCounter';
  3. test('useCounter', () => {
  4. const hookResult = {};
  5. // 创建一个测试组件,仅运行 Hook,不产生任何 UI
  6. const WrapperComponent = () => {
  7. // 将 useCounter 的返回值复制给外部的 hookResult 对象
  8. Object.assign(hookResult, useCounter());
  9. return null;
  10. };
  11. // 渲染测试组件
  12. render(<WrapperComponent />);
  13. // 调用 hook 的 increment 方法
  14. act(() => {
  15. hookResult.increment();
  16. });
  17. // 验证结果为 1
  18. expect(hookResult.count).toBe(1);
  19. // 调用 hook 的 decrement 方法
  20. act(() => {
  21. hookResult.decrement();
  22. });
  23. // 验证结果为 0
  24. expect(hookResult.count).toBe(0);
  25. });
  1. <br />Testing Library 提供的一个专门的 React Hooks 测试包:@testing- library/react-hooks。
  1. import { renderHook, act } from '@testing-library/react-hooks';
  2. import useCounter from './useCounter';
  3. test('useCounter3', () => {
  4. // 使用 renderHook API 来调用一个 Hook
  5. const { result } = renderHook(() => useCounter());
  6. // Hook 的返回值会存储在 result.current 中
  7. // 调用加一方法
  8. act(() => {
  9. result.current.increment();
  10. });
  11. // 验证结果为 1
  12. expect(result.current.count).toBe(1);
  13. // 调用减一方法
  14. act(() => {
  15. result.current.decrement();
  16. });
  17. // 验证结果为 0
  18. expect(result.current.count).toBe(0);
  19. });
  1. <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br />
  2. <br /> <br /> <br /> <br />
  3. <br /> <br /> <br />