内容简介:由于笔者开发的项目越来越大,公共组件的复用性高,故其稳定性尤为重要。因此,引入单元测试刻不容缓。在做项目单元测试前,笔者参考了网上的一些文章以及官方文档,最后选型为Jest + react-test-renderer + Enzyme。前面说了这么多,是时候上代码了。
单元测试的好处:
- 可保证得到结果的一致性,提高项目、组件稳定性。
- 开发者按单元测试思路去写代码,可清晰代码结构,提高代码的可读性。
由于笔者开发的项目越来越大,公共组件的复用性高,故其稳定性尤为重要。因此,引入单元测试刻不容缓。
单元测试的不好:
- 会占用一定的开发成本,增加开发工作量。
- 旧项目加入单元测试改动很大,会有一定的风险。
- 会有一定的学习成本,对开发者要求比较高。
- 如果在一些复用性很低的组件使用单元测试,成效不大且开发成本高。
选型
在做项目单元测试前,笔者参考了网上的一些文章以及官方文档,最后选型为Jest + react-test-renderer + Enzyme。
-
Jest
Jest 是 Facebook 出品的一个测试框架,相对其他测试框架,其一大特点就是就是集成了 Mocha,chai,jsdom,sinon等功能,内置了常用的测试工具,比如自带断言、测试覆盖率工具,实现了开箱即用。
-
react-test-render
配合react-test-render,Jest 可提供了快照测试功能。
首次运行快照测试,会产生一个可读的快照,再次测试时会通过比对快照文件和新产生的快照判断测试是否通过。
Jest在执行的时候如果发现 toMatchSnapshot 方法,会在同级目录下生成一个__ snapshots__文件夹用来存放快照文件,以后每次测试的时候都会和第一次生成的快照进行比较。
-
Enzyme
React官方已经提供了一个测试 工具 库:react-dom/test-utils。但是用起来不够方便,于是有了一些第三方的封装库,比如Airbnb公司的Enzyme。其两大特点:
- 提供了一套简洁强大的 API,并内置Cheerio
- 实现了jQuery风格的方式进行DOM 处理,开发体验十分友好
三种渲染方法
shallow:浅渲染,是对官方的Shallow Renderer的封装。将组件渲染成虚拟DOM对象,只会渲染第一层,子组件将不会被渲染出来,使得效率非常高。不需要DOM环境, 并可以使用jQuery的方式访问组件的信息
render:静态渲染,它将React组件渲染成静态的HTML字符串,然后使用Cheerio这个库解析这段字符串,并返回一个Cheerio的实例对象,可以用来分析组件的html结构
mount:完全渲染,它将组件渲染加载成一个真实的DOM节点,用来测试DOM API的交互和组件的生命周期。用到了jsdom来模拟浏览器环境
三种方法中, shallow 和 mount 因为返回的是DOM对象,可以用simulate进行交互模拟,而 render 方法不可以。一般 shallow 方法就可以满足需求,如果需要对子组件进行判断,需要使用 render ,如果需要测试组件的生命周期,需要使用 mount 方法。
注意: enzyme 还需要根据React的版本安装适配器,适配器对应表如下:
方案
前面说了这么多,是时候上代码了。
-
目录
笔者在根目录新建一个 unitTest 目录,其目录结构为:
-
jest.config.js:jest配置文件
-
mocks:mock文件目录
-
components:项目的公共组件单元测试用例目录
-
components/__ snapshots __:运行单元测试时自动生成的快照存放目录
-
-
安装(由于笔者是react16版本,所以安装的适配器版本为enzyme-adapter-react-16)
npm install jest enzyme enzyme-adapter-react-16 react-test-renderer
-
配置
Jest支持直接在package.json文件写入配置,但笔者有轻微洁癖,喜欢把配置文件写到 unitTest 里面,方便查找以及阅读。
// package.json { "scripts": { "jest": "jest --config ./unitTest/jest.config.js", // 单元测试 "jestupdate": "jest --config ./unitTest/jest.config.js --updateSnapshot" // 单元测试快照更新 "jestreport": "jest --config ./unitTest/jest.config.js --coverage" // 单元测试并生成覆盖率报告 } } 复制代码
// jest.config.js module.exports = { testURL: 'http://localhost/', setupFiles: [], moduleFileExtensions: ['js', 'jsx'], testPathIgnorePatterns: ['/node_modules/'], testRegex: '.*\\.test\\.js$', collectCoverage: false, collectCoverageFrom: ['src/components/**/*.{js}'], moduleNameMapper: { '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/mocks/fileMock.js', '\\.(css|less|scss)$': '<rootDir>/mocks/styleMock.js' } }; 复制代码
- testURL: jsdom运行url,默认为"about:blank",如果不设置,会在尝试访问localStorage出错。
- setupFiles:运行测试代码前,Jest会先运行setupFile指定的配置文件来初始化测试环境。
- moduleFileExtensions:支持单元测试的文件扩展名。
- testPathIgnorePatterns:匹配忽略文件规则。
- testRegex:匹配测试文件规则。
- collectCoverage:是否生成测试覆盖报告,开启会增加测试时间。
- collectCoverageFrom:指示应收集覆盖率信息的一组文件。如果文件与指定的glob模式匹配,即使此文件不存在测试,也将为其收集覆盖率信息,并且测试套件中从不需要它。
- moduleNameMapper:可用于将模块路径映射到不同的模块。默认情况下,预设将所有图像映射到图像存根模块,但如果找不到模块,可配置此选项。
-
mock文件
// fileMock.js module.exports = {}; 复制代码
// styleMock.js module.exports = {}; 复制代码
-
编写单元测试
// button.test.js import Button from '../../src/common/components/Button'; import renderer from 'react-test-renderer'; import React from 'react'; import { shallow, configure } from 'enzyme'; // shallow(浅渲染,只渲染父组件) import Adapter from 'enzyme-adapter-react-16'; // 适应React-16 configure({ adapter: new Adapter() }); // 适应React-16,初始化 const props = { text: '按钮测试用例', type: 'white', style: { marginTop: 15 }, size: 'big', disabled: false, height: 'middle', isLock: true, cname: 'hello', onClick: () => {} }; describe('test Button', () => { it('button render correctly', () => { const tree = renderer.create(<Button {...props} />).toJSON();// 生成快照 expect(tree).toMatchSnapshot(); // 匹配之前的快照 }); it('button has class', () => { const item = shallow(<Button {...props} />); //浅渲染 expect(item.hasClass('hello')).toBe(true); // 断言有item有hello的className }); }); 复制代码
后记
注意事项:
1、如果不配置testURL,会报错:localStorage is not available for opaque origins
2、本文档只讲述笔者的实践方案以供参考,关于Jest、enzyme的具体介绍、用法可参考
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Go语言实战笔记(二十一)| Go 单元测试
- .NET Core开发实战(第28课:工作单元模式(UnitOfWork):管理好你的事务)--学习笔记
- 学习 Node.js,第 9 单元:单元测试
- Vue 应用单元测试的策略与实践 02 - 单元测试基础
- Vue 应用单元测试的策略与实践 04 - Vuex 单元测试
- Vue 应用单元测试的策略与实践 03 - Vue 组件单元测试
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。