Jest + Enzyme React 组件测试实践
Posted 小章鱼哥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Jest + Enzyme React 组件测试实践相关的知识,希望对你有一定的参考价值。
≈
最近把组件测试接入到日常开发,提高了项目代码健壮性,可维护性。本人也从0到1收获了组件测试的经验。
本文总结一下最近两周 组件测试 相关的研究,包括:
- Jest + Enzyme 的基本介绍
- Jest + Enzyme 的实践
- Jest 原理浅析
- Jest 生态 & 未来
文章目录
为什么选择Jest & Enzyme?
1. Jest
Jest 是一套Facebook家背书的测试框架。
实际上,编写一个测试用例,我们需要以下准备:
- 一个测试类库
- 一个断言库(assertion)
- 一个测试执行环境(environment)
- 其他(function or module mock, snapshot etc…)
Jest是包含以上(1234)四合一的一款测试框架。
- Jest内置了jsDOM和Node的执行环境。默认开启面向浏览器端的jsDOM环境。
- Jest内置一套断言库,和Jasmine相同语法。
- Jest自带函数和模块的Mock能力;自己发明了一个专门针对组件测试的快照(snapshot)测试;Jest支持热更新;Jest支持多线程测试。
当然Jest也有一些劣势。
2019年另一款很火的测试框架Mocha,自身不带断言库,也不带Func/Module Mock,集成社区相对成熟的断言库Chai和mock库SinonJS之后,非常强大。Chai断言库相较于Jest内置的断言库API更加丰富更加强大,SinonJS的mock的API也十分完善。而且Mocha的不带其他杂七杂八功能的理念,让它十分具有可配置性。
但是最终选择Jest原因有以下几点:
1. 没有最牛逼的框架,只有最合适的框架。
- 对于组件库的项目,我们对于组件测试的需求非常大,包括组件API的测试和组件呈现效果的测试。Jest自带的snapshot的测试,很亮眼,会把组件渲染的DOM解析成JSON作为快照保存,下一次再获得新的DOM的JSON序列,与旧的序列进行对比,保证组件的呈现的稳定性。
- 组件库的测试很少涉及到网络请求,server端测试,目前是一个纯浏览器端的测试需求。所以Jest自带的断言能力,mock能力够用。而且据我所知,Jest是有一个叫做jest-extend的断言库扩展包。甚至,自己手写就好了。
2. 更简单的配置,更快地上手。
- 实现一个snapshot,只需一句话:expect(component).toMatchSnapshot(),很简单。
- 断言库来自Jasmine,很精炼,够用,简单。
3. 实际上Jest的可配置化也非常强。
- Jest有自己的生态建设(Jest Community)。目前可以配置更加强大的断言扩展,更加灵活的运行环境,甚至还有snapshot使用svg保存的拓展(实际上Jest有倾向做真正的视觉测试,像素比较???好酷鸭)
- Jest自身的配置文件可配置项非常多。我就通过Jest的config配置文件把一个storybook文章生成文件mock成测试用例了哈哈(理论上讲,任何文件都可以变成测试文件)。
4. MVVM框架支持度
- 目前Jest支持市面上主流的开发框架:Vue,React,Angular。babel支持的就是它支持的,因为它提供transform功能。使用jest-babel插件然后利用本地babel配置做文件转换皆可。(也就是说,理论上讲,支持市面上拥有babel转换插件的任何MVVM框架)。
2. Enzyme
Enzyme是Airbnb家的React组件用例测试渲染库。
实际上React官方对于React components的测试有暴露一些库:
react-dom/test-utils
: 拥有一些看一遍也不知道怎么用的API。react-test-render
:可以无渲染环境的基础下,通过shallow渲染拿到WHATWG规范的DOM树结构。React团队利用这个库和Jest团队一起努力打造了React的snapshot test。
Enzyme底层就是封装了以上两个库,却拥有简单精巧的API,打败了React家自带的test render(API设计的力量!React家也一直在安利Enzyme…)。它一共有三个大API:
- shallow:浅渲染。只渲染根级,不渲染子集,它就是封装的
react-test-render/shallow
,生成的是虚拟DOM。 - mount:完整DOM渲染。拥有DOM API交互能力。
- render:静态渲染。用来分析html结构。snapshot请使用这个API。
Enzyme对于以上三种渲染方式都有详细介绍的小API查询。
最终选择Enzyme原因很明确了,这是目前为止最简单上手,功能最强大的React components render库了。
Jest + Enzyme 的实践
1. 配置开发
2. 调试
- 一篇troubleShoot: https://jestjs.io/docs/en/troubleshooting
Jest一些十分有用的Config:
3. Transform
Jest实际上可以测试任意文件:只要你的文件可以通过transform,得到的结果可以被Jest的断言库语法解析。因此一个Markdown,txt等等文件都可以被测试。
4. Mock
Jest默认会mock所有node_modules目录下的依赖文件。我们既可以在config配置文件中配置全局mock规则,也可以在测试用例编写的时候mock某一个function或module。
Jest在内部是这样处理的:拿到file code之后,包一层函数,传入重写的require,export函数。把mock的代码接在code前面。然后一起执行?。
Jest 原理浅析
Jest一共有30多个package,从零开始看你会疯掉。如果想要研究的话,推荐看去年底,Jest官方发布的架构原理视频:https://jestjs.io/docs/en/architecture, 粗略地讲了其中几个重要的包的功能,以及一个测试用例如何被初始化,添加Mock,调度,最终执行的过程。核心内容就是下面这张图。
1. Jest的本质与Jasmine
Jest本身其实是基于Jasmine库之上封装的,Jest的断言库和具体的测试用例执行过程都是Jasmine做的。Jest本身做的是以下事情:
- CI封装
- code transform
- 更抽象的project config
- 多线程调度通信
- jsdom和node以及可以灵活配置的envrionment
- snapshot
- …
(现在还会出现栈溢出的问题,对此Jest的做法是加一个100ms的timeout解决我的天。我在用Jest的时候,snapshot稳稳栈溢出,需要加一个enzyme-to-json/serializer
解决。
Jasmine是BDD(behavior-driven development行为驱动开发)的javascript测试框架。Jasmine非常轻量,本身只有20KB。Jest目前的断言语法都是来自于Jasmine。它定义有如下两种语法:
- describe:内部定义为一个Suite。是一堆测试块的集合。
- it:内部定义为一个Spec。是一个测试块。
以下是一段测试用例代码:
describe("A suite", function()
it("contains spec with an expectation", function()
expect(true).toBe(true);
););
非常语义化,不用看API都能看懂,类似Regular English,这就是BDD。
它拿到用户配置,首先会正则匹配到所有符合要求的文件,抽取出一颗树processTree,因为它支持Suite的嵌套,所以它会先遍历这棵树,做一次order更新,然后用捕获冒泡的方式从树根遍历到树叶再从树叶的father节点再遍历到树根,在它的context下执行测试用例。目的是把测试report通知到所有祖先Suite,最后打出一份Report。(但是,你不要以为Jasmine体积小就好阅读了,Jasmine的源码就是一坨回调地狱。我认为它可以选择重构。)
2. Jest Own Test Runner与Flux
Jest独立出来的其中一个包,就是图中所说的jest-circus。我们可以通过配置选择circus而不是jasmine, 它将要替代Jasmine???
Circus is a flux-based test runner for Jest that is fast, easy to maintain, and simple to extend.
官方说Circus更加快,好维护,易拓展。它支持用户接入任何自定义的执行环境。
import NodeEnvironment from 'jest-environment-node';
import Event, State from 'jest-circus';
// 自定义的环境
class MyCustomEnvironment extends NodeEnvironment
//...
handleTestEvent(event: Event, state: State)
if (event.name === 'test_start')
// ...
它使用了Flux的思想,自己维护了一个state,然后通过事件的Emitter去更新state,没有回调地狱的存在。所以它说:
Mutating event or state data is currently unsupported and may cause unexpected behavior or break in a future release without warning. New events, event data, and/or state data will not be considered a breaking change and may be added in any minor release.
它只支持不可变数据和函数。
Jest 生态 & 未来
Jest有自己的平台https://jestjs.io/docs/en/jest-platform,提供了一些工具函数。
未来的话,Jest有倾向:
- 在snapshot的基础上做视觉测试。
- 多项目测试。比如同时用jest起一个server端和browser端的测试。
- 解决测试时间问题。
以上是关于Jest + Enzyme React 组件测试实践的主要内容,如果未能解决你的问题,请参考以下文章
使用 Jest / Enzyme 在 React 中的功能组件内部测试方法
使用 Jest/Enzyme 在 React 功能组件中测试封闭组件
使用 Jest 和 Enzyme 测试使用 Redux 的功能性 React 组件
使用 React Suspense 和 React.lazy 子组件进行 Jest/Enzyme 类组件测试