单元测试
使用 Jest 和 React Testing Library 进行单元测试
Jest
Facebook 推出的 js 但愿测试框架,零配置就能提供并发测试,测试覆盖率,Mock 工具,断言 API 等。
- Jest 从哪里寻找测试文件
- 如何创建一个测试用例,并用断言验证测试结果
- 如何运行测试
比如在 src 下有一个 add.js 的文件:
export default (a, b) => a + b;
再在 src 目录下创建一个add.test.js
文件,Jest 会寻找 src 目录下以.test.js(ts, jsx, tsx)
结尾的文件,以及 tests 文件夹内的文件,并将其作为测试文件。
// add.test.js
import add from "./add";
// 使用test函数创建一个测试用例
test("renders learn react link", () => {
const s = add(1, 2);
// Jest提供的expect函数断言结果等于3
expect(s).toBe(3);
});
创建完测试用例之后可以在项目根目录通过命令**npx jest —coverage
**来运行测试。
但是这仅仅是纯 js 的逻辑测试,对于 React 应用需要浏览器环境的组件需要引入 Test Library 了。
React Testing Library
- 需要有一个浏览器运行环境:主要通过 jsdom 这样一个 npm 模块去实现,可以在 nodejs 环境中提供一个虚拟的浏览器环境。
- 需要能够解析 JSX
- 需要能够方便地渲染一个 React 组件,并对结果进行验证
项目中自带的 App.test.js:
import {render, screen } from ‘@testing-library/react’
import App from './App'
test('renders learn react link', () => {
render(<App />)
const linkele = screen.getByText(/learn react/i)
expect(linkele).toBeTheDocument();
})
三个 React 相关的测试 API:
- render:用于在内存中 render 一个 React 组件
- screen:提供工具方法用于获取视频上的元素
- expect 扩展:以方便对 UI 元素进行断言判断
对自定义 Hooks 进行单元测试
Hooks 只能在函数组件或者自定义 Hooks 中调用,所以要对 Hooks 进行单元测试,还是需要借助函数组件。
// 对计数器useCounter进行测试
import {render, screen, fireEvent } from ‘@testing-library/react’
test('useCounter', () => {
const testComponent = () => {
const { count, increment, decrement } = useCounter();
return (
<>
<button id="btn-dec" onClick={decrement} />
<span id="result">{count}</span>
<button id="btn-inc" onClick={increment} />
</>
)
}
render(<testComponent />)
const btnDec = document.querySelector('#btn-dec')
const result = document.querySelector('#result')
fireEvent.click(btnDec)
expect(result).toHaveTextContent('-1')
})
如何更直接操锁 Hooks 的 API 呢,可以将 Hook 的返回值暴露道函数组件外:
// 对计数器useCounter进行测试
import {render, screen, fireEvent } from ‘@testing-library/react’
test('useCounter', () => {
const hookResult = {}
const testComponent = () => {
Objext.assign(hookResult, useCounter());
return null
}
render(<testComponent />)
act(() => {
hookResult.increment()
})
expect(hookResult.count).toBe(1)
})
Testinfg Library 也提供了 Hooks 测试包:@testing-library/react-hooks
该测试包提供了 renderHook 和 act 等方法,能够更加语义化地去创建自定义 Hooks 的单元测试。
常用的第三方工具库
lodash
它提供了非常多的工具函数,可以大大提高开发效率。
使用 keyBy 将数组快速转换成对象
const data = [
{
id: 1,
name: "Ken",
city: "Hangzhou",
},
{
id: 2,
name: "Kenny",
city: "Guangzhou",
},
];
// 将其变成一个以name为key的map结构
import _ from 'lodash'
const byName = _.keyBy(data. 'name')
使用 debounce 函数,实现输入防抖
可以实现只有在用户停止输入后一个很短的时间内才进行 change 操作,以保证更好的用户体验。
<input onChange={_.dobounce((e) => setSearch(e.target.value), 300)} />
使用 template 实现简单的模版引擎
可以方便地实现一些复杂的字符串生成。
可以参考相关的官方文档。
UI 库:Ant Design 和 Material UI
- Material UI:采用了 Google 的 Material Design 的设计语言,但是它的组件库缺少一些高级的功能。
- Ant Design:主打企业级应用的场景,提供了各种高级组件,可以满足企业级的复杂交互应用场景。
react-use
useSearchParams
获取 URL 中的查询字符串。
useEvent
如果用 DOM 的原生 API 去绑定事件,通常需要在组件创建时去监听,再在销毁时取消监听。useEvent 封装了这个逻辑:
useEvent("hashchange", onHashChange);
useCookie
它可以方便地去读取,更新或者删除某个 Cookie。
usePrevious
获取某个 state 的上一个值。