内容简介:当我们编写一个组件的时候,要怎么保证组件功能能达到预期呢?你可能回答:我可以人工测试。但是当经历三四次迭代,当有多人协调开发,当进行重构的时候,如何能快速的验证组件是否依然正确执行?这正是需要自动化测试的原因。无论经历多少次迭代,好的自动化测试都能保证你的组件能够正确执行。A component that is untestable or hard to test is most likely badly designed.
React组件自动化测试
1. 为什么要进行自动化测试
当我们编写一个组件的时候,要怎么保证组件功能能达到预期呢?你可能回答:我可以人工测试。但是当经历三四次迭代,当有多人协调开发,当进行重构的时候,如何能快速的验证组件是否依然正确执行?这正是需要自动化测试的原因。无论经历多少次迭代,好的自动化测试都能保证你的组件能够正确执行。
A component that is untestable or hard to test is most likely badly designed.
经过测试的组件是可靠的,可测的组件的架构是合理的。如果一个组件难以下手编写测试用例,只能证明这个组件的设计是糟糕的。因此,编写测试用例的同时,可以帮助组件开发者发现问题,调整代码使架构更加合理。
2. 自动化测试的基础内容
(1) 自动化测试分类
按照测试方法分类:黑盒测试和白盒测试
黑盒测试也称功能测试,在测试中,把程序看作一个不能打开的黑盒子,在完全不考虑程序内部结构和内部特性的情况下,在程序接口进行测试。用户对内部逻辑并不可见。
白盒测试又称结构测试、透明盒测试、逻辑驱动测试或基于代码的测试。白盒测试是一种测试用例设计方法,盒子指的是被测试的软件,白盒指的是盒子是可视的,你清楚盒子内部的东西以及里面是如何运作的。”白盒"法全面了解程序内部逻辑结构、对所有逻辑路径进行测试。
(2) 测试金字塔
该概念是Mike Cohn 在他的著作《Succeeding with Agile》一书中提出的。
测试金字塔中提到的两件事:
-
编写不同粒度的测试
-
层次越高,你写的测试应该越少
(3) 单元测试
指对软件中的最小可测试单元进行检查和验证。单元测试作为测试金字塔最底层,粒度最小,测试速度最快,属于白盒测试。
大多数单元测试包括四个主体:测试套件describe、测试用例it、判定条件expect、断言结果toEqual。
(4) 测试覆盖率
传统的测试覆盖方法常见的有以下几种:
-
函数覆盖(Function Coverage)
-
语句覆盖(Statement Coverage)
-
决策覆盖(Decision Coverage)
-
条件覆盖(Condition Coverage
3. 前端自动化单元测试工具
Jest
Jest是一个轻量级的JavaScript测试框架,可以应用于Babel, TypeScript, Node, React, Angular, Vue等多种技术栈。
1const sum = require('./sum'); 2 3test('adds 1 + 2 to equal 3', () => { 4 expect(sum(1, 2)).toBe(3); 5});
Enzyme
翻译为“溶解酶”,作为单元测试渗透于代码各个细节。一般使用 Enzyme 中的 mount 或 shallow 方法,将目标组件转化为一个 ReactWrapper对象,并在测试中调用其各种方法:
1import React from 'react'; 2import { expect } from 'chai'; 3import { render } from 'enzyme'; 4 5import Foo from './Foo'; 6 7describe('<Foo />', () => { 8 it('renders three `.foo-bar`s', () => { 9 const wrapper = render(<Foo />); 10 expect(wrapper.find('.foo-bar')).to.have.lengthOf(3); 11 }); 12 13 it('renders the title', () => { 14 const wrapper = render(<Foo title="unique" />); 15 expect(wrapper.text()).to.contain('unique'); 16 }); 17});
4. 编写有价值的React组件单元测试用例
React组件分为四种:
-
展示型业务组件
-
容器型业务组件
-
通用 UI 组件
-
功能型组件
根据业务场景,本文主要针对功能性组件进行阐述。
功能型组件,指的是跟业务无关的另一类组件:它是功能型的,更像是底层支撑着业务组件运作的基础组件,比如文本框组件、按钮组件等。功能性组件,更注重逻辑性,UI比较没有那么偏重。功能性组件一般包括JS跟CSS两部分内容,CSS部分不作为测试的重点。
功能性组件必须测试的三部分:
-
Props传入;
-
组件分支渲染逻辑;
-
事件调用和参数传递。
以上三部分测过后,将会达到较高的测试覆盖率。
本文以Karma+Webpack+Mocha+Chai+Sion+istanbul-instrumenter-loader解决方案作为示例演示如何覆盖以上功能性组件测试的三部分。
首先建立一个简单的Input组件,包含label跟input两个标签,可以定义label跟input的值。
1import React from 'react'; 2import PropTypes from 'prop-types'; 3 4export default class TextInput extends React.Component { 5 static propTypes = { 6 label: PropTypes.string, 7 defaultValue: PropTypes.string, 8 onChange: PropTypes.func 9 } 10 11 static defaultProps = { 12 label: '', 13 defaultValue: '' 14 } 15 16 onChange(e) { 17 var val = e.target.value; 18 19 if (this.props.onChange) { 20 this.props.onChange(val); 21 } 22 } 23 24 25 render() { 26 const {label, defaultValue, onChange} = this.props; 27 return ( 28 <div> 29 { 30 label ? (<label>{label}</label>) : null 31 } 32 <input defaultValue={this.props.defaultValue} onChange={this.onChange.bind(this)} ></input> 33 </div> 34 ) 35 } 36}
首先,测试Props是否正确传入。
1it('Validate attributes of the TextInput', () => { 2 const props = { 3 label: '测试', 4 defaultValue: '测试值' 5 } 6 const wrapper = mount(<TextInput {...props}/>); 7 expect(wrapper.find('label').text()).to.equal('测试'); 8 expect(wrapper.find('input').prop('defaultValue')).to.equal('测试值'); 9}); 10
其次,测组件分支渲染。
1 it('Can not render label When label is null', () => { 2 const wrapper = mount(<TextInput />); 3 expect(wrapper.find('label').length).to.be.empty; 4 }); 5 it('Render label When label is not null', () => { 6 const wrapper = mount(<TextInput label='up'/>); 7 expect(wrapper.find('label').length).not.to.be.empty; 8 });
最后,测事件调用。
1 it('Validate onChange event of the TextInput', () => { 2 var temp = ''; 3 const props = { 4 onChange: function(value) { 5 temp = value; 6 } 7 } 8 const wrapper = mount(<TextInput {...props} value='测试值'/>); 9 var input = wrapper.find('input'); 10 input.simulate('change', { target: { value: 'Changed' } }); 11 expect(temp).to.equal('Changed'); 12 }); 13
最后,跑一遍所有的测试用例,均是通过的。然后看下测试覆盖率,分支覆盖率为75%。
进一步打开详情查看,原来是有一部分代码仅有if而没有else,所以这部分未达到100%是可以忽略的。
如果十分介意,可以在if前加入/* istanbul ignore else */。
1 onChange(e) { 2 var val = e.target.value; 3 /* istanbul ignore else */ 4 if (this.props.onChange) { 5 this.props.onChange(val); 6 } 7 }
这样就可以达到100%了。
总结
本文上半部分主要阐述了自动化测试的一些基础知识,下半部分通过一个textinput组件实例,阐述了如何编写有价值的测试用例,达到对组件代码的全覆盖。
参考
React 单元测试策略及落地
https://segmentfault.com/a/1190000016828718
测试金字塔实战
https://insights.thoughtworks.cn/practical-test-pyramid/
前端自动化测试概览
https://juejin.im/entry/5b286a126fb9a00e45113435
对 React 组件进行单元测试
https://juejin.im/post/5a71413e5188252edb593020
Web 前端单元测试到底要怎么写
https://segmentfault.com/a/1190000015935519
7 architectural attributes of a reliable React component
https://dmitripavlutin.com/7-architectural-attributes-of-a-reliable-react-component/#6testableandtested
测试覆盖(率)到底有什么用?
https://www.infoq.cn/article/test-coverage-rate-role
作者简介
南溪,铜板街前端开发工程师,2016年4月加入团队,目前主要负责资金端交易侧 H5项目开发。
---------- END ----------
长按关注我们
以上所述就是小编给大家介绍的《React 组件单元测试》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- React组件单元测试
- 单元测试反应组件
- Vue 应用单元测试的策略与实践 03 - Vue 组件单元测试
- 记一次简单的vue组件单元测试
- 论如何进行小程序自定义组件的单元测试
- 论如何进行小程序自定义组件的单元测试
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
微信公众号深度解析
魏艳 / 化学工业出版社 / 2017-5 / 49.80元
本书是一本微信公众号营销的教科书,全方位揭秘了微信订阅号、微信服务号、微信企业号三大类型账号的运营管理策略和技巧,有助于企业构建一套全新的微信公众号营销体系,打造一个移动端的商业帝国,是企业和微商必读的微信公众号营销和运营宝典。 《微信公众号深度解析:订阅号+服务号+企业号三号运营全攻略》突出了“新”、“全”、“实战”三大特点,阐述了微信公众号在新形势下的现状、发展趋势和三大类型;微信公众号......一起来看看 《微信公众号深度解析》 这本书的介绍吧!