E2E 端到端测试学习 - E2E 介绍、Cypress 案例基本使用

article/2025/11/11 2:31:55

E2E 测试介绍

E2E

E2E(end to end)端到端测试是最直观可以理解的测试类型。在前端应用程序中,端到端测试可以从用户的视角通过真实浏览器自动检查应用程序是否正常工作。

E2E 把整个系统当作一个黑盒,测试人员模拟真实用户在浏览器中操作 UI,测试在真实浏览器环境运行测试,测试出的问题可能是前端也可能是后端导致的,比如:

  • 用户登录注册
  • 加入购物车
  • 订单结算

E2E 测试一般是由 QA 测试工程师来做。稍小的项目可能根据测试用例(excel)操作一遍就完了,稍大一点的会些一些自动化测试的代码。

前端可能会为核心的、主要的或稳定的业务流程写 E2E,不过占据的测试比例要小很多,主要目的是:

  • 便于给 PM(产品经理) 展示业务流程
  • 便于修改 Bug 之后的回归测试

E2E 测试优点

  • 真实的测试环境,相比集成测试和单元测试,更容易获得程序的信心

E2E 测试缺点

  • 端到端测试运行不够快
    • 启动浏览器需要占用几秒钟,网站响应速度又慢。通常一套端到端测试需要 30 分钟的运行时间。如果应用程序完全依赖于端到端测试,那么测试套件将需要数小时的运行时间。
  • 调试比较困难
    • 要调试端到端测试,需要打开浏览器并逐步完成用户操作以重现 bug。本地运行这个调试过程就已经够糟糕了,如果测试是在持续集成服务器上失败,而不是本地计算机上失败,那么整个调试过程将会变得更加糟糕。

流行的端到端测试框架

  • Selenium - 专业 QA 人员使用较多
    • 大部分使用 Python 编写测试
    • 基于 WebDriver,测试用例运行在浏览器外部,通过 WebDriver 协议与运行在浏览器内部的被测应用程序进行交互。
  • Cypress - 目前最流行的适合前端开发工程师的工具
    • 运行在浏览器内部,直接与被测应用程序进行交互。
    • 支持的浏览器没有 Selenium 多
    • 使用 JavaScript 语言(相比使用 Python/Java 的测试工程师不方便)
    • 不支持多页面、多窗口等问题。
    • 本质上是实现了前端开发测试代码的工具。
  • Nightwatch
  • WebdriverIO
  • Playwright - 微软新推的测试化工具
    • 和 Selenium 一样使用 WebDriver 协议,支持浏览器多
    • 社区拥抱,期待值高

本文主要通过 Cypress 学习 E2E 测试。

安装 Cypress

官方文档:Installing Cypress

简单使用没必要特意安装到某个前端项目,可以单独安装,运行真实浏览器环境,测试某个网站,这个网站可以是本地的,也可以是在线的。

mkdir cypress-demo
cd cypress-demo
npm init -y
npm i -D cypress

配置启动脚本:

"scripts": {"cypress:open": "cypress open"
},

运行命令: npm run cypress:open,会打开测试运行器(一个浏览器窗口),INTEGRATION TESTS 显示初始生成的测试用例文件,默认不运行

在这里插入图片描述

可以点击任意测试模块,它会打开一个浏览器窗口(Chrome)运行测试,左边是当前的测试概况,右边是一个真实的浏览器(地址栏+页面)

在这里插入图片描述

当 cypress 启动后,默认会在项目根目录下创建一个 cypress 目录,其中包含 4 个子目录:

├─ fixtures # 存放测试之前准备的测试数据
│   └─ example.json
├─ integration # 存放测试代码文件,可以通过子目录的方式进行分类
│   ├─ 1-getting-started
│   │   └─ todo.spec.js
│   └─ 2-advanced-examples
│       ├─ ...
│       └─ window.spec.js
├─ plugins # 配置 cypress 插件
│   └─ index.js
└─ support # 相关支持配置├─ commands.js└─ index.js

Cypress 基本使用

官方文档:Writing Your First Test

添加一个测试文件

integration 目录下创建测试文件 sample_spec.js

测试运行器会实时加载,创建完成后会显示这个测试文件。

在这里插入图片描述

可以打开运行这个测试文件,测试窗口也会实时加载。

编写第一个测试代码

// describe it 使用的 Mocha
describe('My First Test', () => {it('Does not do much!', () => {// 断言使用的 chaiexpect(true).to.equal(true)})
})

一些 API 看上去和 Jest 很像,但其实 Cypress 中默认 describeit 使用的 Mocha,expect 使用的 chai,如果想要使用 Jest 可以进行配置。

查看测试窗口:

在这里插入图片描述

如果编写一个失败的错误 expect(true).to.equal(false)

在这里插入图片描述

会显示具体哪里导致的错误和文件地址,点击文件还可以用配置的编辑器打开测试用例文件,跳转到对应的代码位置。

编写一个真实测试

describe('My First Test', () => {it('Does not do much!', () => {// 访问一个页面cy.visit('http://npmjs.com/')// 查询一个元素cy.contains('Build amazing things')})
})

保存后观察测试窗口更新,可以看到右侧加载了页面。

即使没有添加断言,测试用例仍然成功,这是因为 Cypress 的许多命令如果没有找到预期的结果,在运行就会失败,这被称为默认断言。

如果编写一个错误测试,如查询页面上没有的内容 cy.contains('123'),测试将失败,但是会等待大于 4 秒后才给出结果,因为内容显示可能需要时间或异步加载,所以 Cypress 默认会等待 4 秒

丰富用例:

describe('My First Test', () => {it('Does not do much!', () => {// 访问一个页面cy.visit('http://npmjs.com/')// 查询一个元素cy.contains('Build amazing things')// 找到输入框,输入内容并按下回车// .get(选择器) 类似于 jQuery 的 $(选择器)cy.get('[placeholder="Search packages"]').type('cypress{enter}')// 断言内容cy.contains('Cypress.io end to end testing tool')})
})

切换浏览器

Cypress 会自动识别系统中安装的浏览器,并允许切换:

在这里插入图片描述

在 Vue 应用中使用 Cypress

案例搭建

可以使用这个案例代码 gothinkster/vue-realworld-example-app,它是 realworld 案例的 Vue 版本。

代码中样式表 https://demo.productionready.io/main.css 从外部站点引入,如果有跨域限制,可手动拷贝到本地。

clone 或下载 zip 源码,npm i安装依赖,npm run serve 运行应用。

配置 Cypress

可以使用 Vue CLI 在创建应用的时候选择安装 Cypress。

已有的项目,也可以手动安装配置 Cypress。

或者使用官方提供的插件:e2e-cypress

# 在项目中安装插件
npx @vue/cli add e2e-cypress
# 如果全局安装了 @vue/cli 可以直接使用 vue 命令安装
# vue add e2e-cypress

安装完成后,查看项目:

1、package.json 中增加了插件依赖和启动命令:

{..."scripts": {..."test:e2e": "vue-cli-service test:e2e"},"devDependencies": {..."@vue/cli-plugin-e2e-cypress": "^5.0.4"}
}

2、项目中新增了 Cypress 的配置文件 cypress.json,里面指定了一个插件文件,在运行测试后的时候会加载这个插件:

{"pluginsFile": "tests/e2e/plugins/index.js"
}

3、还在 tests 目录下创建了 e2e 目录,存放Cypress 的代码,其中测试文件存放在 specs 中,其中包含一个示例文件。

在这里插入图片描述

describe('My First Test', () => {it('Visits the app root url', () => {cy.visit('/')// cy.contains('h1', 'Welcome to Your Vue.js App')})
})

4、运行测试命令 npm run test:e2e

该命令会将应用进行打包构建,Cypress 测试的就是打包后的应用,构建完成后,就会启动测试打开测试运行器。

配置 IDE 代码智能提示

官方介绍了如何配置 IDE 的代码智能提示功能:Intelligent Code Completion

在文件顶部添加注释(三斜杠):

/// <reference types="Cypress" />

修改 DOM 命令等待时间

对基于 DOM 的命令,Cypress 默认等待 4 秒,案例中有些操作需要等待接口响应,而响应时间可能要久一些,可以修改默认等待时间:

// cypress.json
{"pluginsFile": "tests/e2e/plugins/index.js","defaultCommandTimeout": 10000
}

测试用户登录功能

给 Login 页面的元素添加 data-testid

src\views\Login.vue

<ul v-if="errors" class="error-messages"><li data-testid="error-message-item" v-for="(v, k) in errors" :key="k">{{ k }} {{ v | error }}</li>
</ul>
<form @submit.prevent="onSubmit(email, password)"><fieldset class="form-group"><inputclass="form-control form-control-lg"type="text"v-model="email"placeholder="Email"data-testid="email"/></fieldset><fieldset class="form-group"><inputclass="form-control form-control-lg"type="password"v-model="password"placeholder="Password"data-testid="password"/></fieldset><buttondata-testid="submit"class="btn btn-lg btn-primary pull-xs-right">Sign in</button>
</form>

编写测试用例

// tests\e2e\specs\test.js
/// <reference types="Cypress" />describe('用户登录', () => {it('登录成功,跳转到首页', () => {// 打开登录页cy.visit('#/login')// 输入邮箱cy.get('input[data-testid="email"]').type('zby@renshijian.com')// 输入密码cy.get('input[data-testid="password"]').type('123456')// 按下登录按钮cy.get('button[data-testid="submit"]').click()// 断言:当前 url 包含 `#/`cy.url().should('contain','#/')// 断言:页面包含指定元素cy.contains('h1','conduit')})it('登录失败,展示错误提示信息', () => {cy.visit('#/login')cy.get('input[data-testid="email"]').type('zby@renshijian.com')cy.get('input[data-testid="password"]').type('@123456')cy.get('button[data-testid="submit"]').click()// 断言:页面包含指定元素cy.get('[data-testid="error-message-item"]').should('exist').should('contain', 'email or password is invalid')})
})

测试发布文章

给元素添加 data-testid

src\views\ArticleEdit.vue

<form @submit.prevent="onPublish(article.slug)"><fieldset :disabled="inProgress"><fieldset class="form-group"><inputdata-testid="article-title"type="text"class="form-control form-control-lg"v-model="article.title"placeholder="Article Title"/></fieldset><fieldset class="form-group"><inputdata-testid="article-description"type="text"class="form-control"v-model="article.description"placeholder="What's this article about?"/></fieldset><fieldset class="form-group"><textareadata-testid="article-body"class="form-control"rows="8"v-model="article.body"placeholder="Write your article (in markdown)"/></fieldset><fieldset class="form-group"><inputdata-testid="article-tag"type="text"class="form-control"placeholder="Enter tags"v-model="tagInput"@keypress.enter.prevent="addTag(tagInput)"/><div class="tag-list"><spanclass="tag-default tag-pill"v-for="(tag, index) of article.tagList":key="tag + index"><i class="ion-close-round" @click="removeTag(tag)"/>{{ tag }}</span></div></fieldset></fieldset><buttondata-testid="article-publish":disabled="inProgress"class="btn btn-lg pull-xs-right btn-primary"type="submit">Publish Article</button>
</form>

编写测试用例

describe.only('发布文章', () => {it('发布成功,跳转到文章详情页', () => {// 准备登录状态const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InpieUByZW5zaGlqaWFuLmNvbSIsInVzZXJuYW1lIjoi5ZGo56eJ5LmJIiwiaWF0IjoxNjQ4NTM0NTc5LCJleHAiOjE2NTM3MTg1Nzl9.cjPX0Rq4O2jjFNZULL93DwJ8aP3wXig89QZYqL91_CE'window.localStorage.setItem('id_token', token)cy.visit('#/editor')const articleTitle = '这是一篇文章'cy.get('[data-testid="article-title"]').type(articleTitle)cy.get('[data-testid="article-description"]').type('文章描述')cy.get('[data-testid="article-body"]').type('文章内容')cy.get('[data-testid="article-tag"]').type('aa{enter}').type('bb{enter}').type('cc{enter}')cy.get('[data-testid="article-publish"]').click()cy.contains('h1', articleTitle)})
})

http://chatgpt.dhexx.cn/article/dgiM3odV.shtml

相关文章

Unity射线与UI碰撞检测

问题产生背景&#xff1a;我们有的时候&#xff0c;需要实现射线与3D UI之间的碰撞&#xff0c;当射线碰撞到3D UI之后&#xff08;将Canvas设置为World Space&#xff09;&#xff0c;调整到合适的位置。使用LineRender表示射线的直观显示&#xff0c;使用一把枪结合第一人称控…

unity中射线碰撞检测总结

这阵子通过看视频&#xff0c;看书对unity中射线碰撞检测&#xff0c;有了一些了解&#xff0c;这里我把它总结一下写下来&#xff0c;希望能帮助到你们&#xff0c;也希望通过各位大神来指正不足之处&#xff1b; 射线碰撞检测&#xff0c;就是由某一物体发射出一道射线&#…

Unity 射线与碰撞范围检测【踩坑记录】

射线检测 射线检测在2D和3D的区别比较大 一定要加上对应的Collider组件 对应的函数只检测对应的Collider&#xff0c;Physics.Raycast是不会检测到Collider 2D的&#xff08;这个让我有一次debug了好久才发现&#xff09; 对应API如下 Physics.Raycast(Vector3 origin,Vec…

Unity 碰撞位置

获取碰撞位置的方法1&#xff1a;使用 Collider.ClosestPoint Returns a point on the collider that is closest to a given location. 返回碰撞器上最接近给定位置的点。 下方是子弹打到物体上&#xff0c;生成撞击火星的代码&#xff1a; // 碰撞体的检测 private void O…

Unity入门7——物理系统之碰撞检测

一、刚体 Rigid Body ​ 刚体利用体积&#xff08;碰撞器 Collider&#xff09;进行碰撞计算&#xff0c;模拟真实的碰撞效果&#xff0c;产生力的作用 ​ 碰撞产生的必要条件&#xff1a; 两个物体都有碰撞器 Collider至少一个物体有刚体 Mass&#xff1a;质量 默认为千克&a…

解决Unity物体速度过快无法进行碰撞检测(碰撞检测穿透)

一、解决碰撞检测穿透方法一 首先我们知道只要是跟碰撞相关的基本都是离不开刚体 Rigidbody这个组件&#xff0c;刚体中有一个参数适用于检测碰撞的 如下图 Collision Detection就是碰撞检测。 然而有时候开发游戏&#xff0c;对于高速运动的物体&#xff08;比如&#xff…

【Unity】Unity中获得碰撞体碰撞的位置

有时间的直接看sprite slicer这个插件的代码&#xff0c;原理也是发射线检测&#xff0c;代码逻辑什么的比下面的文章来的好的多&#xff0c;如果有空我也可以整理一下。 在纯物理环境中&#xff0c;为了获得碰撞体碰撞的位置&#xff0c;我们可以使用Collider2D.OnCollisionE…

Unity 3D中的射线与碰撞检测

在我们的游戏开发过程中&#xff0c;有一个很重要的工作就是进行碰撞检测。例如在射击游戏中子弹是否击中敌人&#xff0c;在RPG游戏中是否捡到装备等等。在进行碰撞检测时&#xff0c;我们最常用的工具就是射线&#xff0c;Unity 3D的物理引擎也为我们提供了射线类以及相关的函…

unity3D之简单的碰撞检测 .

版权声明&#xff1a;欢迎订阅公众号【5厘米的理想】&#xff0c;愿生命里的每一个小理想&#xff0c;都能成为生命里的小确幸。本文地址为&#xff1a; http://blog.csdn.net/qinyuanpei/article/details/23093665 大家好&#xff0c;欢迎大家关注由我为大家带来的Unity3D游戏…

Unity碰撞检测的必要条件

Unity中有两个独立的物理引擎&#xff0c;一个用于3D物理系统&#xff0c;一个用于2D物理系统。两个引擎是使用不同的组件实现的。因此BoxCollider和Rigidbody一起使用&#xff0c;代码中用OnTriggerEnter才能检测到触发;BoxCollider2D和Rigidbody2D一起使用&#xff0c;代码中…

Unity3D入门(二):碰撞检测

碰撞器由来 1.系统默认会给每个对象(GameObject)添加一个碰撞组件(ColliderComponent)&#xff0c;一些背景对象则可以取消该组件。 2.在unity3d中&#xff0c;能检测碰撞发生的方式有两种&#xff0c;一种是利用碰撞器&#xff0c;另一种则是利用触发器。这两种方式的应用非…

Unity碰撞检测机制的原理(更新中...)

总是碰到关于碰撞的问题&#xff0c;今天实在忍不住了&#xff0c;来把它搞懂&#xff0c;不然听到八叉树&#xff0c;BSP什么的就怕可不行。 转自&#xff1a;http://www.manew.com/thread-102595-1-1.html 碰撞机制 最近做动态地形生成的时候&#xff0c;发现碰撞检测无效&…

Unity 3D之碰撞检测

一、碰撞器 碰撞检测两大必备条件&#xff1a;1.其中一方具备刚体&#xff0c;碰撞双方碰撞器 1、刚体 2、盒子碰撞器 3、碰撞检测方法 void Start(){this.gameObject.AddComponent<Rigidbody>();//添加刚体}void OnCollisionEnter(Collision other){if (other.gameOb…

Unity2d 学习笔记(四)碰撞检测

碰撞检测功能在游戏开发里是比较常用的&#xff0c;比如地图上无法穿越的部分&#xff0c;以及对于敌人的攻击判定等等。这篇博客就开简单介绍一下碰撞事件的处理。 参考视频&#xff1a;Unity碰撞检测_哔哩哔哩_bilibili 首先&#xff0c;我们需要为想要进行碰撞检测的对象添…

2022-04-20 Unity入门7——物理系统之碰撞检测

文章目录 一、刚体 Rigid Body二、碰撞器 Collider三、物理材质四、碰撞检测函数五、刚体加力 一、刚体 Rigid Body ​ 刚体利用体积&#xff08;碰撞器 Collider&#xff09;进行碰撞计算&#xff0c;模拟真实的碰撞效果&#xff0c;产生力的作用 ​ 碰撞产生的必要条件&…

Unity3D —— 碰撞检测

&#xff08;一&#xff09;两种碰撞检测方式 &#xff08;1&#xff09;Collider&#xff1a;碰撞器 ➜需要与刚体一起添加到游戏对象上才能触发碰撞&#xff0c;没有碰撞体的刚体会彼此相互穿过。 碰撞信息检测函数&#xff1a; //碰撞开始 void OnCollisionEnter(Collis…

【Unity入门】24.碰撞检测

【Unity入门】碰撞检测 大家好&#xff0c;我是Lampard~~ 欢迎来到Unity入门系列博客&#xff0c;所学知识来自B站阿发老师~感谢 &#xff08;一&#xff09;碰撞体 &#xff08;1&#xff09;Collider组件 上节课我们有学习到&#xff0c;unity的物理系统提供了更方便的碰撞…

Unity3D教程:简单的碰撞检测

需求&#xff1a;当立方体Cube碰到地面Plane的时候&#xff0c;输出碰撞物体的名称&#xff0c;则表述检测到立方体碰撞了地面。 1.搭建一个简单的场景。 在新的工程中选择File->new Scene创建新的场景。然后在该场景中添加地板&#xff1a;GameObject->Create Other-&…

Unity学习笔记(二) 碰撞检测与触发检测

正好看到了Roll a ball这个游戏&#xff0c;于是就温故一下碰撞检测和触发检测 1.前期准备 中间省去建造一些基础的物体的过程&#xff0c;最后呈现如下图 我们的主角就是中间的球体 其GameObject名为player,我们在其身上添上刚体组件(Rigidbody)使其可以进行物理移动 …

Python实战——过采样数据的处理之改进的SMOTE算法

文章目录 1 理论2 实现3 补充3.1 原理介绍3.1.1 欠采样与过采样3.1.2 Tomek Link 法欠采样3.1.3 Random Over Sampling 随机过采样3.1.4 SMOTE 过采样3.1.5 综合采样 3.2 Python实战3.2.1 数据探索3.2.2 不同的抽样方法对训练集进行处理3.2.2.1 拆分自变量与因变量3.2.2.2 抽样…