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 />![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)
<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);
// 验证结果是不是 1
expect(result).toHaveTextContent('1');
// 模拟点击减一按钮
fireEvent.click(btnMinus);
// 验证结果是不是 0
expect(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,不产生任何 UI
const WrapperComponent = () => {
// 将 useCounter 的返回值复制给外部的 hookResult 对象
Object.assign(hookResult, useCounter());
return null;
};
// 渲染测试组件
render(<WrapperComponent />);
// 调用 hook 的 increment 方法
act(() => {
hookResult.increment();
});
// 验证结果为 1
expect(hookResult.count).toBe(1);
// 调用 hook 的 decrement 方法
act(() => {
hookResult.decrement();
});
// 验证结果为 0
expect(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 来调用一个 Hook
const { result } = renderHook(() => useCounter());
// Hook 的返回值会存储在 result.current 中
// 调用加一方法
act(() => {
result.current.increment();
});
// 验证结果为 1
expect(result.current.count).toBe(1);
// 调用减一方法
act(() => {
result.current.decrement();
});
// 验证结果为 0
expect(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 />