React 现代化测试
测试的动机
测试用例的书写是一个风险驱动的行为, 每当收到 Bug 报告时, 先写一个单元测试来暴露这个 Bug, 在日后的代码提交中, 若该测试用例是通过的, 开发者就能更为自信地确保程序不会再次出现此 bug。
测试的动机是有效地提高开发者的自信心。
前端现代化测试模型
前端测试中有两种模型, 金字塔模型
与奖杯模型
。
金字塔模型摘自 Martin Fowler's blog, 模型示意图如下:
金字塔模型自下而上分为单元测试、集成测试、UI 测试, 之所以是金字塔结构是因为单元测试的成本最低, 与之相对, UI 测试的成本最高。所以单元测试写的数量最多, UI 测试写的数量最少。同时需注意的是越是上层的测试, 其通过率给开发者带来的信心是越大的。
奖杯模型摘自 Kent C. Dots 提出的 The Testing Trophy, 该模型是笔者比较认可的前端现代化测试模型, 模型示意图如下:
奖杯模型中自下而上分为静态测试、单元测试、集成测试、e2e 测试, 它们的职责大致如下:
静态测试
: 在编写代码逻辑阶段时进行报错提示。(代表库: eslint、flow、TypeScript)单元测试
: 在奖杯模型中, 单元测试的职责是对一些边界情况或者特定的算法进行测试。(代表库: jest、mocha)集成测试
: 模拟用户的行为进行测试, 对网络请求、获取数据库的数据等依赖第三方环境的行为进行 mock。(代表库: jest、react-testing-library)e2e 测试
: 模拟用户在真实环境上操作行为(包括网络请求、获取数据库数据等)的测试。(代表库: cypress)
越是上层的测试给开发者带来的自信是越大的, 与此同时, 越是下层的测试测试的效率是越高的。奖杯模型综合考虑了这两点因素, 可以看到其在集成测试中的占比是最高的。
基于用户行为去测试
书写测试用例是为了提高开发者对程序的自信心的, 但是很多时候书写测试用例给开发者带来了觉得在做无用功的沮丧。导致沮丧的感觉出现往往是因为开发者对组件的具体实现细节进行了测试, 如果换个角度站在用户的行为上进行测试则能极大提高测试效率。
测试组件的具体细节会带来的两个问题:
- 测试用例对代码
错误否定
; - 测试用例对代码
错误肯定
;
以轮播图组件
为例, 依次来看上述问题。轮播图组件伪代码如下:
class Carousel extends React.Component {state = {index: 0}/* 跳转到指定的页数 */jump = (to: number) => {this.setState({index: to})}render() {const { index } = this.statereturn <><Swipe currentPage={index} /><button onClick={() => this.jump(index + 1)}>下一页</button><span>`当前位于第${index}页`</span></>}
}
如下是基于 enzyme
的 api 写的测试用例:
import { mount } from 'enzyme'describe('Carousel Test', () => {it('test jump', () => {const wrapper = mount(<Carousel><div>第一页</div><div>第二页</div><div>第三页</div></Carousel>)expect(wrapper.state('index')).toBe(0)wrapper.instance().jump(2)expect((wrapper.state('index')).toBe(2)})
})
恭喜, 测试通过✅。某一天开发者觉得 index
的命名不妥, 对其重构将 index
更名为 currentPage
, 此时代码如下:
class Carousel extends React.Component {state = {currentPage: 0}/* 跳转到指定的页数 */jump = (to: number) => {this.setState({currentPage: to})}render() {const { currentPage } = this.statereturn <><Swipe currentPage={currentPage} /><button onClick={() => this.jump(currentPage + 1)}>下一页</button><span>`当前位于第${currentPage}页`</span></>}
}
再次跑测试用例, 此时在 expect(wrapper.state('index')).toBe(0)
的地方抛出了错误❌, 这就是所谓的测试用例对代码进行了错误否定
。因为这段代码对于使用方来说是不存在问题的, 但是测试用例却抛出错误, 此时开发者不得不做'无用功'来调整测试用例适配新代码。调整后的测试用例如下:
describe('Carousel Test', () => {it('test jump', () => {...- expect(wrapper.state('index')).toBe(0)
+ expect(wrapper.state('currentPage')).toBe(0)wrapper.instance().jump(2)
- expect((wrapper.state('index')).toBe(2)
+ expect((wrapper.state('currentPage')).toBe(2)})
})
然后在某一天粗心的小明同学对代码做了以下改动:
class Carousel extends React.Component {state = {currentPage: 0}/* 跳转到指定的页数 */jump = (to: number) => {this.setState({currentPage: to})}render() {const { currentPage } = this.statereturn <><Swipe currentPage={currentPage} />
- <button onClick={() => this.jump(currentPage + 1)}>下一页</button>
+ <button onClick={this.jump(currentPage + 1)}>下一页</button><span>`当前位于第${index}页`</span></>}
}
小明同学跑了上述单测, 测试通过✅, 于是开心地提交了代码。结果上线后线上出现了问题! 这就是所谓测试用例对代码进行了错误肯定
。因为测试用例测试了组件内部细节(此处为 jump
函数), 让小明误以为已经覆盖了全部场景。
测试用例错误否定
以及错误肯定
都给开发者带来了挫败感与困扰, 究其原因是测试了组件内部的具体细节所至。而一个稳定可靠的测试用例应该脱离组件内部的实现细节, 越接近用户行为的测试用例能给开发者带来越充足的自信。相较于 enzyme, react-testing-library 所提供的 api 更加贴近用户的使用行为, 使用其对上述测试用例进行重构:
import { render, fireEvent } from '@testing-library/react'describe('Carousel Test', () => {it('test jump', () => {const { getByText } = render(<Carousel><div>第一页</div><div>第二页</div><div>第三页</div></Carousel>)expect(getByText(/当前位于第一页/)).toBeInTheDocument()fireEvent.click(getByText(/下一页/))expect(getByText(/当前位于第一页/)).not.toBeInTheDocument()expect(getByText(/当前位于第二页/)).toBeInTheDocument()})
})
关于 react-testing-Library
的用法总结将在下一章节 Jest 与 react-testing-Library 具体介绍。如果对 React 技术栈感兴趣, 欢迎关注个人博客。
相关链接
- write-tests
- Testing
- Testing Implementation Details
- why-i-never-use-shallow-rendering
- react-testing-1-best-practices
转载于:https://www.cnblogs.com/MuYunyun/p/11406989.html
React 现代化测试相关推荐
- react jest测试_如何使用React测试库和Jest开始测试React应用
react jest测试 Testing is often seen as a tedious process. It's extra code you have to write, and in s ...
- react jest测试_如何使用Jest和react-testing-library测试Socket.io-client应用程序
react jest测试 by Justice Mba 由Mba法官 如何使用Jest和react-testing-library测试Socket.io-client应用程序 (How to test ...
- react jest测试_如何设置Jest和Enzyme来测试React Native应用
react jest测试 by Sam Ollason 通过萨姆·奥拉森(Sam Ollason) This short article shares my experiences setting u ...
- enzyme react 组件测试
enzyme 简单实践 enzyme 主要用于 React 组件测试 文档链接:https://enzymejs.github.io/enzyme/ https://www.npmjs.com/pac ...
- mounty不可重新挂载因为先前没有完全卸载_【译】React Hooks测试完全指南
原文地址:https://www.toptal.com/react/testing-react-hooks-tutorial 2018年底,React在16.8版本中引入了Hooks.它们(译注:指R ...
- react dispatch_React测试的那些事(三) React Hook 测试实例
useReducer 测试 useReducer 首先需要在组件中用 actions 和 reducers ,代码如下. Reducer import * as ACTIONS from './act ...
- 在React中测试和调试
测试:Facebook推荐Jest来测试React代码.下面是Jest和Mocha 的比较--还有一篇文章是关于如何在Mocha 中使用Enzyme 的.Enzyme 是Airbnb使用的一个Java ...
- 【500强外资金融科技中心】Seeking研发(Java/React Native)/测试/DevOps/项目管理/架构师
关于深圳保诚科技 深圳保诚科技有限公司 深圳保诚科技是英国保诚集团亚洲金融科技中心. 英国保诚集团(简称"保诚集团/Prudential")于1848年在伦敦成立,是一家国际金融集 ...
- Jest + Enzyme React 组件测试实践
≈ 最近把组件测试接入到日常开发,提高了项目代码健壮性,可维护性.本人也从0到1收获了组件测试的经验. 本文总结一下最近两周 组件测试 相关的研究,包括: Jest + Enzyme 的基本介绍 Je ...
最新文章
- ack strom 保证只有一次_Storm容错机制(一):ACK机制
- 黄埔大学,选址定了!
- 导出勾选密码永不过期的AD账户信息
- 验证数字的正则表达式集
- [题解]BZOJ1004 序列函数
- QT学习:认识QMainWindow
- [css] 用css3实现伪3D的文字效果
- UnixLinux技术文章目录(2015-12-22更新)
- Gartner发布2022年政府行业主要技术趋势:XaaS、数字化、超自动化等
- c ++向量库_将向量复制到C ++中的另一个向量
- HTTP响应头信息 Content-Type
- Vue TodoList案例
- cass道路设计教程_cass道路设计
- 基带信号传输之码间串扰
- 如何理解掩码、反掩码、通配符
- ad18常用快捷键可以修改吗_AD18快捷键
- 学习 PixiJS — 动画精灵
- 计算机制图孔中心线,NX制图(11):如何创建各种中心线?(一)
- osgearth]样式表style中参数总结(OE官方文档翻译)
- 个人案例 装修公司官网
热门文章
- nba全明星java_【NBA·全明星】全明星赛完整名单出炉
- javascript专题
- 数据结构与算法Java版学习教程,最适合新手入门(通俗易懂)
- H.266/VVC变换量化部分内容总结
- 硬盘虚拟化设置被禁用/Intel VT-x可能被禁用。
- 流年似水的wanglf的诗文 幽夜
- flowcontainer: 基于python3的pcap网络流量特征信息提取库
- truncate命令简介
- 安兔兔html5测试排行榜,安兔兔系统评测排行榜(速览最新手机跑分排行榜)
- rabbitmq官网下载教程(手把手教你如何找到资源不迷路)