前言
哈喽,大家好,我是海怪。
刚开始我在写项目的单测方案的时候,老板就让我能够写一些单测的规范。虽然表面上我非常自然地说:没问题,但是心里还是慌得不行:以前我自己写单测也没啥规范呀,直接开干就好了。
最近一直在看 Kent 的文章,刚好看到他写的这篇 《Common mistakes with React Testing Library》,里面列举了很多别人写单测时经常犯的一些错误 。正好可以作为单测规范的参考。所以,今天就把这篇文章也分享给大家~
翻译中会尽量用更地道的语言,这也意味着会给原文加一层 Buf,想看原文的可点击 这里。
正片开始
哈喽,大家好。以前的我(Kent)并不是很喜欢那个时候的测试环境,为此写了一个 React Testing Library。它是原来 DOM Testing Library 的一个扩展,随着不断更新迭代,现在 Testing Library 的实现也能支持当下所有流行的 JS 框架和工具来定位组件中的 DOM 了。
随时代发展,我们也对这个库的 API 做了很多修改,同时也发现社区中有很多不怎么优雅的使用方式。虽然我们已经很努力地在文档里写要怎么 “更好地” 使用我们提供的工具 API,但我还是在别的文章和博客中看到他们在用这些不优雅的使用方法。接下来,我就一一盘点这些方法,解释为什么它们不是很好,以及如何改进测试以避免这些陷阱。
注:下面是重要程度的说明。
- 低:一般为我的主观想法,如果你觉得使用上没啥问题可以忽略它
- 中:如果你不遵循,可能会出现 Bugs、低效的测试用例、还可能会做额外的工作
- 高:一定要用我建议的方法。不然很有可能你会遇到大问题,而且测试用例并不怎么高效
没有使用 Testing Library 的 ESLint 插件
重要程度:中
如果你想避免这些常见的错误,那么官方的 ESLint 插件可以给你带来很多帮助:
注:如果你已经在用
create-react-library
,那eslint-plugin-testing-library
已经包含包在依赖中了
建议:最好把这两个 ESLint 插件都装上。
还在用 Wrapper
作为 render
返回值的变量名
重要程度:低
// ❌
const wrapper = render(<Example prop="1" />)
wrapper.rerender(<Example prop="2" />)
// ✅
const {
rerender} = render(<Example prop="1" />)
rerender(<Example prop="2" />)
Wrapper
是以前 Enzyme 的过时用法,现在已经不需要它了。而且 render
的返回值里也并没有 Wraper
任何东西,它只是一些工具 API 的集合而已。所以,一般情况下可以不需要它了。
建议:直接使用从
render
返回值解构出来的东西,或者将返回值命名为view
。
手动使用 cleanup
重要性:中
// ❌
import {
render, screen, cleanup} from '@testing-library/react'
afterEach(cleanup)
// ✅
import {
render, screen} from '@testing-library/react'
现在cleanup
都是自动调用的,所以你已经不再需要再考虑它了。详见这里。
建议:别手动调
cleanup
不用 screen
重要程度:中
// ❌
const {
getByRole} = render(<Example />)
const errorMessageNode = getByRole('alert')
// ✅
render(<Example />)
const errorMessageNode = screen.getByRole('alert')
screen
是在 DOM Testing Library v6.11.0 引入的 (就就是说,你可以在 @testing-library/react@>=9
这些版本中使用它)。直接在 render
引入的时候一并引入就可以了:
import {
render, screen} from '@testing-library/react'
使用 screen
的好处是:在添加/删除 DOM Query 时,不需要实时地解构 render
的返回值来获取内容。输入 screen
,你的编辑器就能自动补全它里面的 API 了。
除非一种情况:你在配置 container
或者 baseElement
。不过,你应该避免使用它们(因为我实在想不出使用它们的现实场景,除非你是在处理一些历史遗留问题)。
你也可以直接调 screen.debug
而不是 debug
。
建议:用
screen
来做 Querying 和 Debugging
使用错误的断言 API
重要程度:高
const button = screen.getByRole('button', {
name: /disabled button/i})
// ❌
expect(button.disabled)