前端为什么要单测
前端开发和所有其他的软件开发是一样的,为了保障项目交付时代码的质量,需要通过一些测试用例来保证代码在所有的边界情况下都能正常运行。
我们不需要使用测试驱动开发这种极端的模式,但是如果在一开始就有书写测试用例的意识和习惯,就能保证我们更规范的去书写代码的逻辑。
方案选择
对于React的单测方案,可能很多人下意识的会选择 Jest + Enzyme 的方案,Jest 是 Facebook 开源的测试框架,而 Enzyme 是Airbnb 开源的React的测试工具库。他们带有大厂的光环,一度也是React组件首选的测试方案。
但是Airbnb 已经退出Enzyme,现在它已经变成个人项目。并且Enzyme 使用了很多React的内部函数,对于hooks的支持也不是很友好,并且issues的解决速度也让人担忧,所以Enzyme现在已经不是测试React的首选工具库了。
React Testing Library
最近几年,RTL受到越来越多的关注,并且被越来越多的公司和开源项目采纳,CRA已经内置了RTL。
RTL更多的关注使用者怎么去使用一个React组件,以及组件在页面中具体的DOM表现。对于一个React组件的测试,开发者不用再去关心React的内部实现,只要根据组件的真实使用场景去书写对应的单测就可以了,大大减少了单测用例的书写难度。
它没有像Enzyme提供的过多API和复杂的概念,它封装了常用的DOM操作,以及一些常用的断言方法,可以和Jest进行很好的结合。
开始测试
我们有一个组件Input,在antd Input组件的基础上,增加了一个预览态的功能
快照
很多情况下,我们可以通过组件的快照来保证组件渲染的唯一性,当一个组件的dom结构改变时,可以通过快照对比快速的反应出来
import React from 'react';
import { render, asFragment } from '@testing-library/react';
import Input from './input';
test('input snapshot', () => {
const { container } = render(<Input />);
expect(container.firstChild).toMatchSnapshot();
//expect(asFragment()).toMatchSnapshot();
});
通过上面的这个例子,我们引出了render方法。这个方法是RTL的一个核心方法,用来渲染需要测试的React组件。其中返回的container用一个div包裹了包组件真实的dom结构,这个对象也可以访问querySelector等原生的dom方法。
通过toMatchSnapshot这个方法,在运行单测的时候,会自动生成组件的.snap
文件,如果dom结构改变,在再次运行的时候会报错,需要通过-u
的命令参数来强制更新快照文件。
也可以使用asFragment来生成快照。
一个简单的用例
对于组件的测试,我们可以从组件最终的渲染结果来入手
import React from 'react';
import { render, screen } from '@testing-library/react';
import Input from './input';
test('input preview', () => {
render(<Input isPreview value="input preview" />);
// screen.debug();
expect(screen.getByText('input preview')).toBeInTheDocument();
});