前言
- 测试分类
- 测试开发方式
- 测试覆盖率
一. 测试分类
前端的测试可以分为 4 类:单元测试、集成测试、端到端测试 和 快照测试
单元测试
单元测试是对应用程序最小的部分(单元)进行测试的过程。
通常,测试的单元是函数,但在前端应用中,组件也是被测单元。
单元测试的好处:
提升代码质量、保证代码的整洁清晰、让代码维护更容易(提高代码的可读性、可维护性、鲁棒性)
上库前的保证,找出潜在的bug、消灭低级错误
有助于代码的模块化设计
业务代码梳理和重构的过程(不断的优化测试用例和代码)
在频繁的需求变动中可控地保障代码变动的影响范围
单元测试的缺点:
会占用一定的开发成本,增加开发工作量。
旧项目加入单元测试改动很大,会有一定的风险。
会有一定的学习成本,对开发者要求比较高。
如果在一些复用性很低的组件使用单元测试,成效不大且开发成本高
由于单元测试是独立的,所以无法保证多个单元运行到一起是否正确
常见的 JavaScript 单元测试框架:
Jest
Jasmine
Karma
Mocha
ava
Tape
Mocha 跟 Jest 是目前最火的两个单元测试框架,基本上目前前端单元测试就在这两个库之间选了。
总的来说就是 Jest 功能齐全,配置方便,Mocha 灵活自由,自由配置。
两者功能覆盖范围粗略可以表示为:
Jest === Mocha + Chai(断言库) + Sinon(函数mock库) + istanbul(代码覆盖率统计库)
集成测试
简单来说:
前端页面就是由一系列的组件组合在一起的,所以所谓的集成测试,其实就是测试这个组件放在一起,是否能够正常工作。
优点:
由于是从用户使用角度出发,更容易获得软件使用过程中的正确性
集成测试相当于写了软件的说明文档
由于不关注底层代码实现细节,所以更有利于快速重构
相比单元测试,集成测试的开发速度要更快一些
缺点:
测试失败的时候无法快速定位问题
代码覆盖率较低
速度比单元测试要慢
端到端测试
E2E(end to end)端到端测试是最直观可以理解的测试类型。
在前端应用程序中,端到端测试可以从用户的视角通过浏览器自动检查应用程序是否正常工作。
优点:
真实的测试环境,更容易获得程序的信息
缺点:
首先,端到端测试运行不够快。启动浏览器需要占用几秒钟,网站响应速度又慢。
通常一套端到端测试需要 30 分钟的运行时间。
如果应用程序完全依赖于端到端测试,那么测试套件将需要数小时的运行时间。
端到端测试的另一个问题是调试起来比较困难。
要调试端到端测试,需要打开浏览器并逐步完成用户操作以重现 bug。
一些流行的端到端测试框架:
Cypress
Puppeteer
PhantomJS
Nightwatch
WebdriverIO
playwright
快照测试
快照测试类似于“找不同”游戏。
快照测试会给运行中的应用程序拍一张图片,并将其与以前保存的图片进行比较。
如果图像不同,则测试失败。这种测试方法对确保应用程序代码变更后是否仍然可以正确渲染很有帮助。
当然,在前端中,其实并不是比较图片,而是比较前后生成的html结构,本质上是一个字符串的比较。
哪些场景会用到快照测试呢?
典型的就是组件库中,例如:ant design,vant等其实每个组件都会有对应的快照测试。
实际开发中的总结: 如果你是开发纯函数库,建议写更多的单元测试 + 少量的集成测试 如果你是开发组件库,建议写更多的单元测试、为每个组件编写快照测试、写少量的集成测试 + 端到端测试 如果你是开发业务系统,建议写更多的集成测试、为工具类库、算法写单元测试、写少量的端到端测试
二. 测试开发方式
TDD:
测试驱动开发 Testing Driven Development
先写测试后实现功能
强调的是一种开发方式,以测试来驱动整个项目,即先根据接口完成测试用例编写,
然后再完成功能, 要不断通过测试,最终目的是通过所有测试
流程:
1. 先写测试用例
2. 再写业务代码
3. 再重构代码和测试用例
4. 循环优化...
BDD:
行为驱动开发 Behavior Driven Development
先实现功能后写测试
强调的是写测试的风格,即测试要写的像自然语言,让项目的各个成员甚至产品都能看懂测试,甚至编写测试
TDD和BDD有各自的使用场景:
BDD一般偏向于系统功能和业务逻辑的自动化测试设计;
而TDD在快速开发并测试功能模块的过程中则更加高效,以快速完成开发为目的。
个人推荐:
建议开发组件库、函数库使用 TDD 方案;
建议开发业务系统使用 BDD 方案;
而适合引入测试场景大概有这么几个:
需要长期维护的项目。它们需要测试来保障代码可维护性、功能的稳定性
较为稳定的项目、或项目中较为稳定的部分。给它们写测试用例,维护成本低
被多次复用的部分,比如一些通用组件和库函数。因为多处复用,更要保障质量
三. 测试覆盖率
最著名的测试覆盖率就是代码覆盖率。这是一种面向软件开发和实现的定义。
它关注的是在执行测试用例时,有哪些软件代码被执行到了,有哪些软件代码没有被执行到。
被执行的代码数量与代码总数量之间的比值,就是代码覆盖率。
这里,根据代码粒度的不同,代码覆盖率可以进一步分为四个测量维度。它们形式各异,但本质是相同的。
● 行覆盖率(line coverage):是否每一行都执行了?
● 函数覆盖率(function coverage):是否每个函数都调用了?
● 分支覆盖率(branch coverage):是否每个if代码块都执行了?
● 语句覆盖率(statement coverage):是否每个语句都执行了?
例子
// app.js
function fn(a, b) {
if ((a + b) > 2) {
console.log('more than two');
} else {
console.log('less than two');
}
}
fn(1, 1)
"test": "istanbul cover app.js",
执行 npm run test
可以看出 Statement、Branches、Lines都有一行没有执行到,再打开覆盖率文件夹coverage中的index.html可以看到如下图所示,if语句中有一条没有执行到
更改代码:
function fn(a, b) {
if ((a + b) > 2) {
console.log('more than two');
} else {
console.log('less than two');
}
}
fn(1, 1)
fn(1, 2)
覆盖率都已经到达100%了