进阶篇:前端自动化测试
测试指在应用开发完成后,通过人工或者程序的手段,校验软件是否存在缺陷、bug,验证产品行为是否符合业务预期,规避功能异常给用户、业务带来损失。
自动化测试,就是脱离人工操作,依靠测试工具与测试代码自动执行校验逻辑。前端自动化测试即在预设环境(包含正常、异常场景)下运行前端业务代码、页面组件,自动完成校验,输出测试结果,最大程度减少人工介入。
自动化测试核心价值:提升代码质量、稳定性与可维护性;把重复的人工校验交给机器,做到执行速度快、可反复执行、问题定位清晰。
为什么要做前端自动化测试
前端项目普遍依赖开发人员自测、测试人员手工回归。
手工测试的优势是可以直观看到页面视觉表现,人的主观感受更容易发现体验类问题。但存在明显短板:
- 人为容易出现疏漏、误判;
- 回归测试成本极高,迭代改动后需要全部功能重新测一遍;
- 版本频繁迭代,重复机械的校验工作消耗大量人力。
自动化测试不能完全替代手工测试,但可以补足短板。
自动化测试优势:
- 保障代码逻辑正确性,提升项目质量;
- 测试用例一次编写,反复执行;
- 测试用例本身可以作为文档,帮助新人理解业务逻辑;
驱动编码设计,反向推动代码解耦、具备可测试性。 自动化测试劣势:
需要投入成本编写、维护测试代码;
- UI视觉、主观交互体验场景,自动化很难完全覆盖。
自动化收益公式:自动化的收益 = 迭代次数 × 全部手动执行成本 − 首次自动化成本 − 维护次数 × 维护成本,只有当收益大于成本时,引入自动化测试才有实际意义。
什么样的项目适合引入自动化测试
自动化不是万能银弹,不是所有项目都适合投入。 引入前要评估投入产出比,一般满足下面多数条件才适合:
- 核心业务逻辑稳定,需求不会频繁大幅度变更;
- 项目迭代周期较长,有持续维护的生命周期;
- 需要高频做回归测试;
- 代码设计规范,业务模块具备可测试性;
- 测试脚本可以被反复复用。
如果需求改动极其频繁、项目周期很短一次性交付、脚本复用率低,维护测试代码的成本会远大于收益,则不建议大规模做自动化测试。
测试基础分类:黑盒、白盒、灰盒测试
黑盒测试
不关心程序内部代码实现,只校验输入与输出、外部功能表现。
测试者不需要阅读源码,依据产品需求文档设计用例,输入合法、非法数据,观察输出结果是否符合预期。
适用场景:系统测试、集成测试、E2E 端到端测试。
白盒测试
也叫透明盒、结构测试。需要了解程序内部逻辑、代码结构,针对代码分支、执行路径设计用例,校验内部逻辑是否按预期执行。 适用场景:单元测试、模块集成测试。
灰盒测试
介于黑盒、白盒中间。 重点校验输入输出结果,同时会适度关注部分内部状态,但不会完整遍历全部内部逻辑;兼顾效率,不需要像白盒那样深挖每一条代码路径。很多前端集成测试属于灰盒测试。
前端测试分层
按照软件工程由小到大的分层思想,前端测试分为三层:单元测试、集成测试、端到端(E2E)测试。
单元测试(Unit Test)
单元测试针对最小可测试单元做验证,例如一个工具函数、hooks、独立组件。 重点校验:模块接口、内部局部数据、逻辑分支、异常处理、边界条件。一般由开发人员编写,在开发阶段执行。
前端单元测试的特殊点:浏览器 API、BOM、DOM 存在环境差异,因此单元测试经常运行在模拟浏览器环境。
主流单元测试框架:- Mocha:高度灵活的测试运行框架,自身不提供断言、mock 能力,可以搭配 Chai(断言库)、Sinon(模拟桩函数);支持 Node.js 和浏览器双环境运行。
- Jest:开箱即用,内置断言、mock、快照测试,React、Vue 项目广泛使用;测试用快照对比组件输出,降低断言编写成本。
- Jasmine:老牌单元测试框架,自带断言,开箱即用,但对异步场景支持偏弱。
- Karma:测试运行器,可以启动真实浏览器执行测试,一般搭配 Mocha、Jasmine 使用,Angular 官方默认组合。
- Ava:轻量,支持多文件并发执行,但是大项目下 CPU 占用高,生态相对薄弱。 选型参考:Vue、React 项目大多选择 Jest。
集成测试(Integration Test)
在单元测试完成的基础上,把多个模块组装在一起,校验模块之间接口调用、数据传递、协同工作是否正常。 难点:测试颗粒度更大,业务逻辑复杂,外部依赖变多,很难做到完全隔离,测试稳定性会比单元测试差。
适用场景:多个耦合组件组合、二次封装工具、组件联动逻辑。
Vue 组件集成测试工具:
Vue Test Utils:Vue 官方组件测试工具库。Vue Testing Library:基于 DOM-Testing Library,封装适配 Vue,更贴近用户实际使用行为,不推荐直接测试组件内部实例状态,优先操作 DOM 节点断言,鼓励良好测试实践。
端到端测试 E2E(End-to-End)
E2E 站在真实用户视角,完整运行整套应用,访问页面、模拟点击输入等用户操作,校验完整业务链路。会同时覆盖前端页面、后端接口、网络等整套环境,最贴近真实用户使用场景。
特点:可以跨浏览器做真实页面测试;成本最高,执行速度慢,适合核心业务流程。
主流 E2E 测试工具:
- Cypress:直接运行在浏览器内部,开箱即用,自动等待异步操作,自带截图、录屏,调试体验优秀,支持 E2E 也支持组件测试,生态完善。
- Nightwatch.js:基于 W3C WebDriver 标准,驱动真实浏览器,API 简洁,支持 E2E 也支持简单单元测试。
- Puppeteer:谷歌出品,Node 控制 Headless Chrome,一般配合 Jest、Mocha 做二次封装,适合做爬虫、截图、自动化,本身不是完整测试框架。- TestCafe:不需要单独浏览器驱动,配置简单,编写稳定的用户操作测试用例。
Mocha 使用入门
Mocha 是功能丰富的 JavaScript 测试框架,同时支持 Node.js 和浏览器,对异步测试友好,测试用例串行执行,可以搭配任意断言库(Chai、Node 内置 assert)。
npm install mocha --save-dev
// test/index.js
const assert = require('assert');
describe('Array', function () {
describe('#indexOf()', function () {
it('当值不存在应当返回 -1', function () {
assert.equal([1, 2, 3].indexOf(4), -1);
});
});
});
终端运行测试:./node_modules/mocha/bin/mocha。
常用命令:
mocha # 默认执行 ./test 目录测试文件
mocha add.test.js # 指定单个测试文件
mocha test/unit/*.js # 通配符匹配多个测试文件
mocha --recursive # 递归执行test目录下所有子目录脚本
mocha --watch # 监听文件变更自动重跑
mocha --timeout 5000 # 修改异步用例超时时间,默认2000ms
Jest 使用入门
Jest 主打开箱即用,内置断言、mock、快照测试,React、Vue 项目最常用,配置成本低。
npm install jest --save-dev
// test/index.test.js
function sum(a, b) {
return a + b;
}
test('1 + 2 结果等于 3', () => {
expect(sum(1, 2)).toBe(3);
});
终端执行命令:./node_modules/jest/bin/jest.js。
常用执行方式:
jest # 自动识别 __tests__、*.test.js、*.spec.jsjest my-test # 按名称匹配测试用例
jest path/demo.test.js # 指定测试文件
Cypress 使用入门
Cypress 直接运行在浏览器环境,模拟真实用户行为,自动处理异步等待,支持 E2E 端到端测试与组件测试,调试体验优秀。
npm install cypress --save-dev
./node_modules/cypress/bin/cypress open
执行后自动生成项目目录结构,同时弹出可视化 GUI 窗口:
cypress
├─ fixtures # 测试 mock 静态数据
├─ e2e(integration) # 测试用例脚本
├─ plugins # 自定义插件
└─ support # 全局命令、公共钩子
cypress.config.js # 配置文件
describe('Todo页面示例', () => {
beforeEach(() => {
// 每次用例执行前,访问目标页面
cy.visit('https://example.cypress.io/todo');
});
it('页面标题应当是 todos', () => {
cy.get('.todoapp .header h1').should('have.text', 'todos');
});
it('初始列表包含2条待办', () => {
cy.get('.todo-list li').should('have.length', 2);
});
it('输入框可以正常录入文本', () => {
cy.get('.todoapp .header input').type('测试输入');
cy.get('.todoapp .header input').should('have.value', '测试输入');
});
});
Cypress 内置多套断言:Chai BDD、TDD 断言、Chai-jQuery DOM 断言、Sinon-Chai spy、mock 断言,通过 .should() 链式调用完成校验。
Nightwatch.js 简单入门
Nightwatch 基于 W3C WebDriver 协议,驱动真实浏览器完成自动化测试,支持端到端测试,同时也支持简单单元测试。
npm install nightwatch chromedriver --save-dev
备注:需要安装对应浏览器驱动,Chrome 使用 chromedriver;Firefox 使用 geckodriver;Safari 需要执行一次 safaridriver --enable。
describe('搜索引擎测试', function () {
it('搜索关键词', function (browser) {
browser
.url('https://www.ecosia.org/')
.setValue('input[type=search]', 'nightwatch')
.click('button[type=submit]')
.assert.containsText('.mainline-results', 'Nightwatch.js');
});
});
运行测试:./node_modules/nightwatch/bin/nightwatch --env chrome test/index.js。