前端自动化测试Cypress -- 百炼千锤
背景介绍
软件测试是使用人工或自动的手段来运行或测定某个软件系统的过程,其目的在于检验它是否满足规定的需求或弄清预期结果与实际结果之间的差别。 [1]
从是否关心软件内部结构和具体实现的角度划分,测试方法主要有白盒测试和黑盒测试。白盒测试方法主要有代码检査法、静态结构分析法、静态质量度量法、逻辑覆盖法、基本路径测试法、域测试、符号测试、路径覆盖和程序变异。黑盒测试方法主要包括等价类划分法、边界值分析法、错误推测法、因果图法、判定表驱动法、正交试验设计法、功能图法、场景法等。
软件测试分类
1、白盒测试
白盒测试又称结构测试、透明盒测试、逻辑驱动测试或基于代码的测试。白盒测试是一种测试用例设计方法,盒子指的是被测试的软件,白盒指的是盒子是可视的,即清楚盒子内部的东西以及里面是如何运作的。"白盒"法全面了解程序内部逻辑结构、对所有逻辑路径进行测试。"白盒"法是穷举路径测试。在使用这一方案时,测试者必须检查程序的内部结构,从检查程序的逻辑着手,得出测试数据。贯穿程序的独立路径数是天文数字
2、黑盒测试
黑盒测试也称功能测试,它是通过测试来检测每个功能是否都能正常使用。在测试中,把程序看作一个不能打开的黑盒子,在完全不考虑程序内部结构和内部特性的情况下,在程序接口进行测试,它只检查程序功能是否按照需求规格说明书的规定正常使用,程序是否能适当地接收输入数据而产生正确的输出信息。黑盒测试着眼于程序外部结构,不考虑内部逻辑结构,主要针对软件界面和软件功能进行测试。
3、探索性测试
探索性测试可以说是一种测试思维技术。它没有很多实际的测试方法、技术和工具,但是却是所有测试人员都应该掌握的一种测试思维方式。探索性强调测试人员的主观能动性,抛弃繁杂的测试计划和测试用例设计过程,强调在碰到问题时及时改变测试策略。
对探索性测试最直白的定义是:同时设计测试和执行测试。探索性测试有时候会与即兴测试(ad hoc testing)混淆。即兴测试通常是指临时准备的、即兴的Bug搜索测试过程。从定义可以看出,谁都可以做即兴测试。由Cem Kaner提出的探索性测试,相比即兴测试是一种精致的、有思想的过程。
前端测试的类型
单元测试(Unit Test)
单元测试又称为模块测试,主要针对程序中最小可测试单元(一般指方法,类)的测试,具备投入小、收益产出高的特征,可以较早期地发现代码缺陷,适用于公共函数库的测试。
单元测试是最容易实现的:代码中多个组件共用的工具类库、多个组件共用的子组件等。
通常情况下,在公共函数/组件中一定要有单元测试来保证代码能够正常工作。单元测试也应该是项目中数量最多、覆盖率最高的
集成测试
集成测试通常被应用在:耦合度较高的函数/组件、经过二次封装的函数/组件、多个函数/组件组合而成的函数/组件等。
集成测试主要包括模块接口测试,子功能模块集成起来的功能模块测试等,目的是为了验证在单元测试的基础上,所有模块集成起来的子系统、子功能是否仍然满足质量目标。
集成测试的目的在于,测试经过单元测试后的各个模块组合在一起是否能正常工作。会对组合之后的代码整体暴露在外接口进行测试,查看组合后的代码工作是否符合预期。
E2E测试
E2E(end to end) 又称为 “端到端“ 测试的主要目的是从软件使用者角度来检验软件的质量,如打开浏览器,进行一系列的操作,验证界面或功能是否符合预期测试是指端到端测试又叫功能测试,站在用户视角,使用各种功能、各种交互,是用户的真实使用场景的仿真。
在产品高速迭代的现在,有个自动化测试,是重构、迭代的重要保障。对web前端来说,主要的测试就是,表单、动画、页面跳转、dom渲染、Ajax等是否按照期望。
前端自动化测试 --- 蛋卷和金字塔
动化测试是一种测试方法,是指使用特定的软件,去控制测试流程,并比较实际结果与预期结果之间的差异。通过将测试自动化,可以把人对软件的测试行为转化为由机器自动执行测试的行为,从而替代大量的手工测试操作,使得测试可以快速,反复的进行。
蛋卷模型
有一种直接的做法是,既然更加高层的测试覆盖面越广,那么我们就得写更多的高层测试,比如大量的系统测试,这样就能大范围的覆盖掉底层测试。当然依然有一些底层测试是覆盖不了的,所以我们又单独去写单元测试进行补充,这样我们就会形成这样一个模型:冰淇淋蛋卷
但是这种费时费力,有时一个复杂系统的测试链路是异常麻烦的,这时候我们需要的是换一种思路。
金字塔模型
金字塔模型,该模型把测试从下到上分为了单元测试、集成测试和端到端测试(E2E测试/UI界面测试)。越往金字塔底层,测试成本越低,效率也越高,而越往金字塔的顶层,测试成本会逐渐增高,收益也会越低。
前端自动化测试框架抉择
1.1 测试框架的分类
1.1.1 浏览器控制框架
主要是用来控制浏览器或者app上的元素,常见的框架有:
Web: Selenium/TestCafe/Cypress/Playwright/Puppeteer/Protractor/Nightmare
Mobile app: Appium/Robot Framework
1.1.2 管理测试用例设计框架
主要是用来组织测试用例设计以及测试用例的结构,常见的框架有:
All: Cucumber
JS: Mocha/Jest/Jamine/TestCafe/Cypress/CodeceptJS
Ruby: Rspec
Java: TestNG/Junit
Python: pytest
1.1.3 管理测试用例执行框架
主要是用来组织测试用例的执行,常见的框架有:
All: Cucumber
JS: Mocha/Jest/Jamine/TestCafe/Cypress/CodeceptJS
Ruby: Rspec
Java: TestNG/Junit
Python: pytest, unittest
1.1.4 管理测试用例报告框架
主要是用来组织测试结果和展示,常见的框架有:
All: Cucumber/Allure
JS: Mocha/Jest/Jamine/TestCafe/Cypress/CodeceptJS
Ruby: Rspec
Java: TestNG/Junit
Python: pytest, unittest
1.1.5 断言框架
主要是用来测试结果的断言,常见的框架有:
All: Selenium
JS: Chai/Jest/Jamine/TestCafe/Cypress/CodeceptJS
1.1.6 覆盖率框架
主要是用来收集代码覆盖率,常见的框架有:
JS: Istanbul/Jest/blanket
Ruby: Rcov
Java: jacoo / cobertura
1.1.7 可视化测试框架
主要是用来做可视化测试,常见的框架有:
JS: Cypress/CodeceptJS/Applitools
1.1.8 支持Mock/Spy/Stub
主要是用来对请求的东西做mock,常见的框架有:
Sinon/Cypress/CodeceptJS
1.1.9 一体化框架
不需要和其他框架集成,完成整个测试活动, 常见的框架有:
Cypress/CodeceptJS/TestCafe
1.2 各个测试框架的优劣势对比
工具/框架
优势
劣势
Selenium
开源免费
支持多种语言: Java/Python/Ruby/JS...
支持跨平台: Windows/Mac/Linux/Mobile(IOS/Android)
支持多浏览器: Chrome/Firefox/Safari/Edge
支持Headless, CI/CD
测试用例设计: 支持PageObject/快照
测试用例执行:支持并发
上手容易度一般
需要考虑浏览器版本兼容性
不好调试, 执行速度较慢
稳定性一般,不支持Retry
需要和其他测试工具管理测试设计和执行: BDD, e.g: Cucumber
需要和其他测试断言框架结合使用: chai
需要和其他测试执行工具管理测试执行和报告展示: e.g: TestNG/ReportNG
不支持可视化测试
Cypress
一款完整框架,不需要和其他框架一起使用
有开源免费版和收费版,上手较容易
支持跨平台: Windows/Mac/Linux
支持Web/单元/集成测试
浏览器: Chrome/Firefox/Edge/Electron
支持Headless, CI/CD(Edge,xx限制)
测试用例设计: BDD/快照/视频录制
测试用例执行:执行速度较快,支持并发, 本身有各种执行方式,不需要和第三方框架集成; 支持元素全局自动等待;模拟网速
测试用例调试:有可视化的调试窗口
测试稳定性较好:支持Retry
测试结果:很好的报表html页面,支持flaky tests分析, 支持coverage report
支持可视化测试
只支持JS
不支持Safari测试(以后可能会支持)
不支持Mobile测试, 对于mobile web apps的测试兼容性不是很好
测试用例设计:不支持PageObject; 不支持打开多个tab; iframe有些情况会有问题; 不友好支持hover/scroll, file upload;
API/单元测试测试支持不是很友好,如果只是单独做API测试的话不建议使用
CodeceptJS
一款完整框架,不需要和其他框架一起使用
开源免费,上手较容易
支持跨平台: Windows/Mac/Linux
支持Web/Mobile(Android/IOS)/集成测试
浏览器: Chrome/Firefox/Safari/Edge ...
支持Headless, CI/CD
测试用例设计: BDD/快照
测试用例执行:执行速度较快,支持并发, 本身有各种执行方式,不需要和第三方框架集成; 支持元素全局自动等待
测试稳定性较好:支持各种级别的Retry
测试结果:很好的报表html页面
支持可视化测试
灵活切换各种流行driver, 测试维护成本较低(webdriver/playwright/puppeteer/testcafe/appium/nightmare/protractor/api helpers, graphql)
与第三方框架兼容较好,易于扩展
只支持JS
API测试支持不是很友好,如果只是单独做API测试的话不建议使用
某些情况下支持视频录制: 切换不同的driver, e.g: webdriver
不支持模拟网速
测试用例调试没有可视化窗口,但是有调试命令
测试用例报告: 暂时没有coverage report
TestCafe
开源免费,上手较容易
支持跨平台: Windows/Mac/Linux
浏览器: Chrome/Firefox/Safari/Edge/mobile browsers ...
支持Headless, CI/CD
测试用例设计: PageObject/快照/Video
测试用例执行:执行速度较快,支持并发, 支持元素自动等待; 脚本变动会自动执行
独立管理测试用例设计和执行,断言, 测试报告
只支持JS
兼容性: 不支持mobile native apps
原生支持不是很友好,它是一个代理服务器和web浏览器通信
不支持BDD,需要和其他工具集成
不支持可视化测试
Playwright
微软开发,开源免费,上手较容易
支持跨平台: Windows/Mac/Linux
支持多种语言: JS/Java/Python/C#
支持Web/模拟的Mobile(Android/IOS)
浏览器: Chrome/Firefox/Webkit based apps
支持Headless, CI/CD
测试用例设计: 自带Inspector元素
测试用例执行:执行速度较快,支持并发, 支持元素自动等待; 监控模拟网络请求; **支持native mouse/keyboard操作;上传下载文件;**支持跨页面/frame/tab操作, dark mode操作
不支持API测试
测试用例调试没有可视化窗口,但是有调试命令
没有办法独立管理测试用例设计和执行,需要和其他框架
不支持可视化测试
Puppeteer
开源免费,上手比cypress高
支持跨平台: Windows/Mac/Linux
支持Web/Mobile(Android/IOS)/集成测试
浏览器: Chrome/Firefox, 本身安装包和chrome驱动器, 支持浏览器原生操作更多(支持native mouse/keyboard操作;上传文件)
支持Headless, CI/CD
测试用例设计: 快照/BDD
测试覆盖率: 收集前端代码覆盖率
可以收集页面性能数据
下载量很大
支持JS,与其他语言兼容性较差
兼容性: Firefox和其他的浏览器不是很友好
社区活跃度一般
只是一个chrome driver的API,没有办法独立管理测试用例设计和执行,需要和其他框架
Protractor
开源免费,上手比cypress高; 搭建不方便需要和selenium一起使用
为AngularJS app应用开发
支持跨平台: Windows/Mac/Linux
支持Web/Mobile(Android/IOS)
浏览器: 各种浏览器, 支持浏览器原生操作更多(支持native mouse/keyboard操作;上传文件)
支持Headless, CI/CD
只支持JS
没有办法独立管理测试用例设计和执行,需要和其他框架结合使用,e.g: Jasmine/Mocha
Nightmare
一个为浏览器自动化API库
开源免费,上手比cypress高
支持跨平台: Windows/Mac/Linux
浏览器: 使用的是electron engine, 不需要和浏览器兼容
支持Headless, CI/CD
运行速度非常快,很稳定
不能真实反映兼容性
需要和其他测试框架一起使用
只支持JS
Appium
一个为mobile app(Android/IOS)开发的自动化测试框架
多语言支持
开源免费,上手一般,搭建容易度一般
支持图片对比
Robot Framework
一个为mobile app(Android/IOS)开发的自动化测试框架
多语音支持
开源免费,比较容易搭建
2 工具篇
工具整体上来说比框架更容易上手,对测试人员更友好。
但是工具一般都很少免费,而且定制化程度不是很高,有的时候不能满足项目定制化的需要。
Jest
Mocha
Selenium/WebDriver
Nightwatch
TestCafe
Cypress
支持测试类型
单元测试
单元测试
E2E测试
E2E测试、Node.js单元和集成测试
E2E测试
单元测试、集成测试、E2E测试
支持语言
JS、Node
JS、Node
Java、Python、C#、JS
JS、Node
JS、TypeScript
JS
是否支持可视化测试
否
否
否
否
否
是
是否自带断言库
是
否
否
是
否
是
是否开箱即用
是
否
否
是(安装配置繁琐)
是
是
录制生成脚本
/
/
支持
不支持
不支持
不支持
Github Star
35.2k
20.5k
20.8k
10.7k
8.9k
31.3k
文档
Jest文档
Mocha文档
Selenium文档
Nightwatch文档
Testcafe文档
Cypress文档
3、结论
由于Cypress能够同时支持单元测试、集成测试和E2E测试,提供了一套完成的测试解决方案,能够满足我们的需求。此外,Cypress支持JS编写测试用例,支持Jquery元素定位选择器,支持Headless和CI持续集成,运行速度快,上手成本低,并且具有可视化调试界面,方便定位问题
Cypress实践是检验真理的唯一标准
1、安装
yarn add cypress
或者npm install cypress
安装完毕后,
./node_modules/.bin/cypress install
安装cypress环境(包括GUI工具)
2、配置
Cypress主要包含以下两种启动方式:
1)命令行执行npx cypress open:会在浏览器打开测试用例集的界面,需要手动运行。
2)命令行执行npx cypress run:会以无头浏览器模式运行指定的所有测试用例,没有可视化界面,但运行过程中会录制整个测试过程的视频,可在cypress/videos目录下查看。
当然,除了直接在命令行运行上述命令,也可以通过配置package.json的scripts字段来定义启动方式。
package.json: 配置GUI和非GUI(terminal)两种方式来运行cypress
"scripts": { "cypress": "cypress run", "cypress-gui": "cypress open",复制代码
复制代码
⚠️ 配置好后 先运行 yarn cypress[-gui]
或者 npm run cypress[-gui]
(中括号意思是可选)来初始化cypress
,生成默认配置和目录
cypress.json(与package.json同级目录): cypress提供比较灵活的配置,可以根据自己需要定制行为,以下列一下我对一个项目的配置
可视化界面运行
如果我们需要在可视化界面进行测试,在配置好package.json后,只需要执行npm run cypress:open,就可以启动Cypress,实现可视化调试,如果在启动的过程中遇到以下错误,可以先执行npx cypress install -force,再重新启动Cypress。
如果成功启动Cypress,将会看到以下界面,examples目录下是cypress自带的测试用例演示代码(如果后面不需要,我们可以将这些测试用例删除),点击其中的某个测试用例,将会自动打开浏览器运行测试用例。
3、工程目录介绍
4、无头浏览器模式运行
如果我们想以无头浏览器模式运行,在配置好package.json后,需要执行npm run cypress:run,Cypress就会以无头浏览器的模式运行指定的所有测试用例
5、编写测试用例
接下来以验证百度页面的搜索功能为例,演示如何编写测试用例,测试用例可以以.spec.js或.js结尾命名,并放入cypress/integration中。
项目目录如下所示,在cypress/integration中创建test.js或test.spec.js测试用例文件。
接着,可以在test.js中开始编写测试用例,Cypress支持Jquery元素选择器及汉字选择器,并且也支持链式操作,此外,由于Cypress拥有自动等待机制,我们无须在测试中添加wait或sleep,Cypress会自动等待元素至可操作状态时才执行命令或断言。
/// <reference types="cypress" /> context('百度页面测试', () => { it('访问百度页面,验证搜索功能', () => { cy.visit('https://www.baidu.com').then(() => { // 1. 输入搜索内容 cy.get(".s_ipt").should("exist").type("Cypress自动化测试"); // 2. 点击百度一下按钮 cy.get(".s_btn").contains("百度一下").should("exist").click(); // 3. 验证搜索内容不为空 cy.get("#content_left").find("div").then(ele => { expect(ele.length).gt(0); }); }); }); });复制代码
编写完上述代码,我们就可以直接启动Cypress运行啦,当然,我们也可以根据实际需要在cypress.json进行一些配置,下面给出了一些常用的配置,可以在Cypress文档查看更多配置。
最后,执行npm run cypress:open启动Cypress,启动成功后,我们就可以看到以下界面,点击test.js,就会在浏览器中运行该测试用例。
在测试用例执行的过程中,每一步操作都会被记录下来,可以点击左边的界面对每一步的操作进行回看,可以帮助我们快速定位问题。
6、Cypess文件上传/下载
在实际的使用过程中,我们通常也需要验证文件上传或下载功能,而Cypress也能够满足这些需求。
1)文件上传
首先需要安装cypress-upload-file插件。
npm install cypress-upload-file --save-dev复制代码
将要上传的文件放到cypress/fixtures中。
编写测试用例代码。
/// <reference types="cypress" /> context('文件上传', () => { it('验证文件上传功能', () => { // 访问页面,此处步骤省略 let file = "file/cover.jpg"; cy.get("input[type='file']").attachFile(file); // 执行断言,此处步骤省略 }); });复制代码
2)文件下载
若我们在运行测试用例的过程中存在文件下载操作,Cypress会自动在cypress目录下创建一个downloads目录,所下载的文件会自动保存在该目录中。
可以在测试用例中读取并解析下载的文件。
/// <reference types="cypress" /> const path = require("path"); context('文件下载', () => { it('验证文件下载功能', () => { // 访问页面,执行下载操作,此处步骤省略 const downloadsFolder = Cypress.config("downloadsFolder"); const downloadedFilename = path.join(downloadsFolder, "下载文件.xls"); // 读取文件 cy.readFile(downloadedFilename).then(data => { // 执行断言,此处步骤省略 }); }); });复制代码
7、Cypress测试报告
在执行完自动化测试后,我们通常都希望能够得到一份详细的测试报告,而Cypress也能够提供这个功能。Cypress除了内置的测试报告,也支持用户自定义报告格式。
1)内置的测试报告
Cypress内置的测试报告主要包括了spec格式报告(在控制台窗口输出嵌套分级视图),json格式报告(在控制台窗口输出一个大的json对象)和junit格式报告(输出一个xml文件)。以spec格式报告为例,在启动cypress时加上以下参数即可。
2)自定义的测试报告
常用的自定义测试报告有Mochawesome报告,Mochawesome是与Mocha一起使用的自定义报告程序,并与mochawesome-report-generator结合使用以生成独立的HTML/CSS报告。
安装mocha和mochawesome。
npm install mocha --save-dev npm install mochawesome --save-dev复制代码
修改启动参数。
运行npm run cypress:run,执行结束后,会在项目根目录下生成mochawesome-report目录。
在浏览器中打开mochawesome.html,就可以查看可视化测试报告。
可维护的测试脚本
在实际编写测试用例的过程中,随着页面的增多,我们常常会遇到以下这些问题,而这个时候,如何编写可维护的测试脚本,方便后期维护,也显得非常重要,这里也总结了实际开发中的一些经验。
1、测试用例代码结构组织
在编写测试用例时,我们可以一个页面对应一个测试文件,也可以同个功能模块的页面一起对应一个测试文件,并且和平时开发中所采用的代码组织结构类似,将不同的测试文件划分到对应的目录下进行管理,方便后期的维护。
2、页面选择器统一管理
在E2E测试中,我们通常需要获取页面元素,才能够进行点击等操作。而Cypress支持Jquery选择器,我们可以通过元素的class或id定位元素。但是一旦页面的类名或id发生变化,我们不得不修改对应页面的所有测试用例。
在编写测试用例的过程中,我们可以将页面选择器进行统一管理,实现类名或id选择器和逻辑代码的分离。对于每个页面或者每个测试文件,可以创建一个对应的xxxControl.js文件,在该文件中,将会定义一个json对象并且export出来,其中,key为我们自己定义的选择器名称,而value值对应页面中实际的class或id
由于目前项目中使用到了iview组件库,因此也提取出了commonControl.js,对iview的选择器进行统一管理。
由于每个页面都采用到了iview组件,因此每个页面或每个测试文件对应的control.js都需要将上面的commonControl.js引入进来。
最后,每个测试文件只需要引入对应的control.js,就可以通过自己定义的key值获取页面真正的class或id。
上面的方法看起来虽然麻烦了点,但是有两个好处,首先,采用自己定义的key值,更容易方便我们记忆,可以减少编写测试用例过程中反复查看页面元素对应的class或id名。其次,当页面的类名或id发生变化时,我们只需要修改页面对应的control.js文件就可以,而不用修改所有的测试用例文件,有利于后续的维护。
3、路径名及接口统一管理
在编写测试用例的过程中,我们通常需要使用cy.visit()去访问某个页面,或者使用cy.request()去调用后台接口以请求数据或创建测试数据,对于页面url或后台接口api,我们也可以放入某个文件中进行统一管理。
4、代码复用
在测试的过程中,我们可能会注意到,不同的页面可能会存在一些相同的功能。比如像目前的项目中,不同的页面都需要对一些操作进行弹框确认或表单输入,而在验证弹框功能是否正确的过程中,我们都需要对弹框执行点击确定按钮、点击取消按钮、点击关闭按钮等操作,而这个时候就可以采用面向对象编程的方法实现代码的封装和复用。
定义一个弹框类,并且定义属性和方法。
在测试文件中,需要实例化对象,并调用相关的方法完成某个操作。
当然,有些方法并不是所有的页面都共有的,但是在某个页面或功能中会反复使用到,因此也可以为每个页面或每个测试文件单独封装相应的方法。比如为课程管理页面封装相应的通用方法。
作者:玉
链接:https://juejin.cn/post/7038182819599745038
伪原创工具 SEO网站优化 https://www.237it.com/