1、使用 Jest 创建单元测试
<br />主要需要了解以下三点:
- Jest 从哪里寻找测试文件;
- 如何创建一个测试用例,并用断言验证测试结果;
- 如何运行测试。 ```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); })
运行结果:<br /><a name="VHFnY"></a># 2、使用 React Testing Library 测试 React 组件```jsx// 引入 testing-library 提供的相关工具import { render, screen } from '@testing-library/react';// 引入要测试的组件import App from './App';// 创建一个测试用例test('renders learn react link', () => {// 使用 render 方法渲染 App 组件render(<App />);// 通过 screen 提供的 getByText 找到页面上的 DOM 元素const linkElement = screen.getByText(/learn react/i);// 断言这个元素应该在页面上expect(linkElement).toBeInTheDocument();});
Testing Library 提供的三个 React 相关的测试 API:
- render:用于在内存中 render 一个 React 组件。
- screen:提供了工具方法,用于获取屏幕上的元素。比如这里的 screen.getByText,就 是用来根据文本获取 DOM 元素的。
- expect 扩展:Testing Library 扩展了 expect 的功能,以方便对 UI 元素进行断言判 断。比如例子中的 toBeInTheDocument ,就是用于断言 DOM 元素需要存在于 Document 中。
3、如何对自定义 Hooks 进行单元测试
<br />**创建一个测试组件**,**在这个测试组件内部使用这个 Hook**。
import { render, fireEvent, screen } from '@testing-library/react'; import useCounter from './useCounter';test('useCounter', () => {// 创建一个测试组件,使用 useCounter 的所有逻辑const WrapperComponent = () => {const { count, increment, decrement } = useCounter();return (<><button id="btnMinus" onClick={decrement}>-</button><span id="result">{count}</span><button id="btnAdd" onClick={increment}>+</button></>);};// 渲染这个测试组件render(<WrapperComponent />);// 找到页面的三个 DOM 元素用于执行操作以及验证结果const btnAdd = document.querySelector('#btnAdd');const btnMinus = document.querySelector('#btnMinus');const result = document.querySelector('#result');// 模拟点击加一按钮fireEvent.click(btnAdd);// 验证结果是不是 1expect(result).toHaveTextContent('1');// 模拟点击减一按钮fireEvent.click(btnMinus);// 验证结果是不是 0expect(result).toHaveTextContent('0');}
这样做的缺点是我们需要写很多与 Hooks 测试本身无关的代码。 比如页面上的这些 DOM 元素。
我们能否更直接地操作 Hooks 的 API 呢?其实也是可以的。我们可以将 useCounter 这个 Hook 的返回值暴露到函数组件之外,然后由测试代码直接调用这些 API 并验证结果。下面的代码就演示了这种做法:
import { render, act } from '@testing-library/react';import useCounter from './useCounter';test('useCounter', () => {const hookResult = {};// 创建一个测试组件,仅运行 Hook,不产生任何 UIconst WrapperComponent = () => {// 将 useCounter 的返回值复制给外部的 hookResult 对象Object.assign(hookResult, useCounter());return null;};// 渲染测试组件render(<WrapperComponent />);// 调用 hook 的 increment 方法act(() => {hookResult.increment();});// 验证结果为 1expect(hookResult.count).toBe(1);// 调用 hook 的 decrement 方法act(() => {hookResult.decrement();});// 验证结果为 0expect(hookResult.count).toBe(0);});
<br />Testing Library 提供的一个专门的 React Hooks 测试包:@testing- library/react-hooks。
import { renderHook, act } from '@testing-library/react-hooks';import useCounter from './useCounter';test('useCounter3', () => {// 使用 renderHook API 来调用一个 Hookconst { result } = renderHook(() => useCounter());// Hook 的返回值会存储在 result.current 中// 调用加一方法act(() => {result.current.increment();});// 验证结果为 1expect(result.current.count).toBe(1);// 调用减一方法act(() => {result.current.decrement();});// 验证结果为 0expect(result.current.count).toBe(0);});
<br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /> <br /><br /> <br /> <br /> <br /><br /> <br /> <br />
