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.state return <> <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> &