IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> Cypress 前端测试工具的基本使用和相关命令总结 -> 正文阅读

[开发测试]Cypress 前端测试工具的基本使用和相关命令总结


写下博客用于自我复习、总结。
如有错误之处,请各位大佬指出。
学习资料来源于:https://www.cnblogs.com/poloyy/tag/Cypress/


本文主要是自己用于总结用,大部分内容都是直接参考于以下博客链接,各位如有需要,可直接去该博客中学习。

Cypress的官方文档:
https://docs.cypress.io/guides/overview/why-cypress#In-a-nutshell
由于官方文档现在不支持中文,所以目前关于Cypress的使用可以通过这个博客,进行学习和查看:
https://www.cnblogs.com/poloyy/p/14031640.html
https://www.cnblogs.com/poloyy/tag/Cypress/


Cypress介绍

  • Cypress 是基于 JavaScript 的前端测试工具,可以对浏览器中运行的任何内容进行一个快速、简单、可靠的测试;
  • Cypress 是自集成的,提供了一套完整的端到端测试,无须借助其他外部工具,安装后即可快速地创建、编写、运行测试用例,且对每一步操作都支持回看;
  • 不同于其他只能测试 UI 层的前端测试工具,Cypress 允许编写所有类型的测试:界面测试,集成测试,单元测试。

Cypress原理

Cypress 运行测试的大致流程:

1、运行测试后,Cypress 使用 webpack 将测试代码中的所有模块 bundle 到一个 js 文件中;

2、然后运行浏览器,并且将测试代码注入到一个空白页中,然后它将在浏览器中运行测试代码;

3、每次测试首次加载 Cypress 时,内部 Cypress Web 应用程序先把自己托管在本地的一个随机端口上,如:http://localhost:65874;

4、在识别出测试中发出的第一个 cy.visit() 命令后, Cypress 会更改本地 URL 以匹配远程应用程序的 Origin(满足同源策略),这使得测试代码和应用程序可以在同一个 Run Loop 中运行。


Cypress的优势

而我选择去学习 Cypress 进行一个前端测试的原因是:

1、Cypress 本身拥有着快速、简单、可靠的特点,这使得前端开发人员也可以进行简单快速的测试。开发人员只需要 npm 下载一次,后续无需借助任何其他工具,安装后即可快速创建、编写、运行测试用例。

2、Cypress 运行更快的根本原因:
Cypress 测试代码和应用程序均运行在由 Cypress 全权控制的浏览器中,所以 Cypress 的测试代码可以直接操作 DOM、Window Objects、Local Storages 而无须通过网络访问。

3、Cypress 稳定性、可靠性更高的原因:
① Cypress 可以在网络层进行即时读取和更改网络流量的操作;
② Cypress 背后是 Node.js Process 控制的 Proxy 进行转发,这使得 Cypress 不仅可以修改进出浏览器的所有内容,还可以更改可能影响自动化操作的代码;
③ Cypress 相对于其他测试工具来说,能从根本上控制整个自动化测试的流程。
在这里插入图片描述


Cypress的特性

1、拥有历史记录
Cypress 在测试代码运行时会自动保存每一步操作,等测试运行结束后,用户可在 Cypress 提供的 Test Runner 里,通过悬停在命令上的方式查看运行时每一步都发生了什么。

2、实时重新加载
当测试代码修改保存后,Cypress 会自动加载改动地方,并重新运行测试。

3、运行结果一致性
Cypress 架构不使用 Selenium 或 Webdriver,在运行速度、可靠性测试、测试结果一致性上均有良好保障。

4、可调试性
当测试失败时,可以直接从开发者工具(F12 Chrome DevTools)进行调试。

5、自动等待
使用Cypress,永远无须在测试中添加强制等待、隐性等待、显性等待,Cypress 会自动等待元素至可靠操作状态时才执行命令或断言。

6、网络流量控制
Cypress 可以 Mock 服务器返回的结果,无须依赖后端服务器,即可实现模拟网络请求。

总结来说,使用 Cypress,开箱即用,想要的内容全部帮我们封装好了。


Windows下建立一个测试项目

Cypress 是一个被安装在电脑上的桌面应用,操作系统需要满足如下条件才能正常安装:
Mac OS 10.9+(仅提供64位二进制文件)
Linux Ubuntu 12.04+, Fedora 21, Debian 8的64位二进制文件
Windows 7+

安装 Cypress + 创建一个测试项目很简单:
1、新建一个空文件夹
在这里插入图片描述

2、确保系统中已经安装 Node.js

如果未安装可参考我的文章:
https://blog.csdn.net/qq_45613931/article/details/105538861

3、在空文件夹下生成 package.json 文件:npm init,一路回车,最后输入yes
在这里插入图片描述

4、安装 Cypress
npm install cypress --save-dev
或者 cnpm install cypress --save-dev
在这里插入图片描述

5、安装完成。现在项目结构:
在这里插入图片描述

虽然还没有写任何内容,但是我们可以通过接下来的步骤,打开 Cypress,也让 Cypress 帮我们创建好项目结构。

6、打开 package.json 文件,对 scripts 中的内容进行改变:

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

7、打开命令行窗口,在当前项目目录下,运行 Cypress
在这里插入图片描述

8、运行效果:
在这里插入图片描述

9、运行过首次后,目录结构就发生了改变,Cypress 帮我们建好了一个测试用例,里面就有基本的使用方法。
在这里插入图片描述


Cypress的目录结构

查看目录结构:
在这里插入图片描述

1、fixtures 测试夹具
该目录下的内容主要用来存储测试用例的外部静态数据。它通常配合 cy.fixture() 使用。这些测试夹具的静态数据通常存储在 .json 文件中,如自动生成的 example.json。静态数据通常是某个网络请求对应的响应部分,包括HTTP状态码和返回值,一般是复制过来更改而不是自己手工填写。

对于 fixtures 的实际应用场景:
如果测试中需要对某些外部接口进行访问并依赖它的返回值,则可以使用测试夹具而无须真正访问这个接口(有点类似 mock)。

使用测试夹具的好处:
(1)消除了对外部功能模块的依赖
(2)已编写的测试用例可以使用测试夹具提供的固定返回值,并且确切知道这个返回值是我们想要的
(3)无须真正地发送网络请求,测试更快

2、integration 测试文件
该目录下的所有内容,且文件格式是以下的文件都将被 Cypress 识别为测试文件:
.js :普通的JavaScript 编写的文件(常用)
.jsx :带有扩展的 JavaScript 文件,其中可以包含处理 XML 的 ECMAScript
.coffee :一套 JavaScript 转译的语言。有更严格的语法
.cjsx :CoffeeScript 中的 jsx 文件
创建好之后,Cypress 的 Test Runner 刷新之后就可以看到对应测试文件了。
在这里插入图片描述

3、plugins 插件文件
该目录用来存放一些现成的插件,使我们可以修改或扩展 Cypress 的内部行为(如:动态修改配置信息和环境变量等),也可以自定义自己的插件。为了方便,每个测试文件运行之前,Cypress 都会自动加载插件文件。

对于 Cypress 为什么还需要自己设置插件:
之前提到过,Cypress 的独有优点就是测试代码运行在浏览器之内,使得 Cypress 跟其他的测试框架相比,有显著的架构优势。但是,该优点虽然提供了可靠性测试,但也使得和在浏览器之外进行通信更加困难。由此,通过插件就可以帮助我们将信息直接从测试代码传递到后端,或者修改特定浏览器的启动参数等等。

4、support 支持文件
该目录用来放置可重用配置项,如底层通用函数或全局默认配置。为了方便,每个测试文件运行之前,Cypress 都会自动加载支持文件。对于它的使用,只需要在该目录中的 index.js 文件里添加beforeEach() 函数即可。

beforeEach(function(){
    cy.log('测试')
})

5、cypress.json
通常情况下,我们可以不用更改上述的默认目录结构,但实际上我们也可以去自定义它的默认目录结构以及 Cypress 的各项配置。修改这些配置信息,就是在 cypress.json 文件中来实现(文件默认为空)。

配置项可去其他博客和官网查看:
https://www.cnblogs.com/poloyy/p/13024996.html
https://docs.cypress.io/guides/references/configuration#Cypress-config

除了上述各种直接在 cypress.json 文件里更改配置项之外,Cypress 还允许我们通过 Cypress.config() 去获取或覆盖某些配置项,语法如下:

// 获取所有config信息
Cypress.config()
// 获取指定配置项的信息
Cypress.config(name)
// 更改指定配置项的默认值
Cypress.config(name, value)
// 使用对象字面量(object literal)设置多个配置项
Cypress.config(object)

比如,我们在某个测试文件中,就可以查看它,并去修改它:

describe('测试配置项', function () {
    it('测试取值和设置值', function () {
        // 获取 pageLoadTimeout默认值
        cy.log(`${Cypress.config('pageLoadTimeout')}`)

        // 设置 pageLoadTimeout 值
        Cypress.config("pageLoadTimeout",100000)

        // 再次获取 pageLoadTimeout 的值
        cy.log(`${Cypress.config('pageLoadTimeout')}`)
    })
})

Cypress的使用

现在以目前 Cypress 自动生成的目录结构中的todo.spec.js 为例,对这个测试用例进行测试。
1、首先在 Cypress 界面中,找到对应的测试用例。
在这里插入图片描述

2、单击 todo.spec.js 后,Cypress 就会启动 Test Runner 运行测试。运行成功后,我们就可以看到运行结果页面。
在这里插入图片描述

3、调试测试用例
测试用例运行时,难免会发生各种情况导致运行失败,如何快速定位发生错误的位置,了解错误信息,一直是自动化测试的痛点。而 Cypress 提供了多种 debug 能力,可以在测试运行错误时直达错误位置,并支持回放错误发生时的上下文信息,可直接看到测试失败的原因。具体来看:
(1)每个命令均有快照且支持回放
如下图中一样,左侧是测试步骤,右侧是测试页面。当我们鼠标 hover 测试步骤,在右侧就可以看到执行该命令时的页面效果。当我们鼠标点击测试步骤时,可以锁定该步骤,然后查看上下文信息。

在这里插入图片描述

(2)暂停测试并逐步运行、恢复执行
在调试测试代码时,Cypress 提供了命令来暂停测试运行:cy.pause()
比如,我们增加一个暂停测试:
在这里插入图片描述

效果:
在这里插入图片描述

右上角有两个按钮,左边的是 Resume:继续执行测试用例并运行到结束。
右边的是 Next:get:测试会变成逐步运行,点一下只执行下一个命令。


Cypress的基本用法

在总结项目结构时,也简单提到了一些基本命令,现在将主要对这些基本命令的功能和用法进行总结。

首先 Cypress 底层依赖于很多优秀的开源测试框架,其中就有 Mocha。Mocha 是一个适用于 Node.js 和浏览器的测试框架,它使得异步测试变得简单。

而 Cypress 就采纳了 Mocha 的 BDD(行为驱动开发)语法。Cypress 将 Mocha 硬编码在自己的框架中,所以编写测试用例都需要基于 Mocha 提供的基本功能模块。
在这里插入图片描述

接下来就以目前 Cypress 自动生成的目录结构中的todo.spec.js 为例,具体来看其中的常见功能模块。


1、对于一条可执行的测试用例来说,有以下两个必要的组成部分

(1)describe()
describe() 代表一个测试套件,所有的测试内容都需要写在其中。其中,可以包括多个测试用例 it() ,也可以嵌套使用测试套件。但需要注意,其中至少含有一条测试用例 it() 。

(2)it()
代表一条测试用例

比如:

// 测试套件 describe
describe('example to-do app', () => {
  // 一条测试用例 it
  it('displays two todo items by default', () => {

  })
  // 也能嵌套使用
  describe('with a checked task', () => {
    // 一条测试用例 it
    it('can filter for uncompleted tasks', () => {

    })
})
})

效果:
在这里插入图片描述

除了上述两个功能模块外,其他功能模块对于一条可执行的测试来说,都是可选的。


2、context()

context() 是 describe() 的别名,其行为方式是一致的,我们可以直接用 context() 去替代 describe() 。
比如:

// 测试套件 context
context('example to-do app', () => {
  // 一条测试用例 it
  it('displays two todo items by default', () => {})
})

3、 cy.log:输出日志


4、钩子函数

钩子函数的作用就是在所有测试用例执行前做一些预置操作(如:准备测试数据、测试环境)或者在测试结束后做一些后置操作(如:清理测试数据)。

Mocha 提供的 Hook 函数共有四个:
before() :在当前测试套件的第一个测试用例中仅调用一次
beforeEach() :在当前测试套件中的所有测试用例(包括子测试套件)使用前调用
afterEach() :在当前测试套件中的所有测试用例(包括子测试套件)完成后调用
after() :在当前测试套件的最后一个测试用例(包括子测试套件)中仅调用一次

比如:

describe('测试生命周期 - 顶级测试套件', () => {
  before(() => {
    cy.log('顶级测试套件【before】')
  })
  beforeEach(() => {
    cy.log('顶级测试套件【beforeEach】')
  })
  after(() => {
    cy.log('顶级测试套件【after】')
  })
  afterEach(() => {
    cy.log('顶级测试套件【afterEach】')
  })

  it('顶级测试套件 - 打印日志1', () => {
    cy.log('顶级测试套件 - 打印日志1')
  })

  it('顶级测试套件 - 打印日志2', () => {
    cy.log('顶级测试套件 - 打印日志2')
  })

  context('二级测试套件', () => {
    before(() => {
      cy.log('二级测试套件【before】')
    })
    after(() => {
      cy.log('二级测试套件【after】')
    })
    it('二级测试套件 - 打印日志3', () => {
      cy.log('二级测试套件 - 打印日志3')
    })
  })
})

实际效果:
在这里插入图片描述
在这里插入图片描述
总结来说:若包含多级测试套件,那么父级套件、祖父级套件声明的 hook 函数会作用于所有子级套件的测试用例,孙子级套件的测试用例…以此类推。


5、获取元素的方法

现在我们知道了一条测试用例的基本组成 describe、it、context、生命周期钩子函数,随后在测试用例中,首先就需要想办法查找页面元素。比如在这一节中,就以这段代码为例,进行说明:

<button id="main1" class="btn" data-cy="submit">submit</button>
<button id="main2" class="btn" data-test="submit">submit</button>
<button id="main3" class="btn" data-testid="submit">submit</button>
<ul>
    <li id="li1">test1</li>
    <li data-cy="li2">test2</li>
    <li data-test="li3">test3</li>
    <li data-testid="li4">test4</li>
</ul>

在查找页面元素的时候,分为两大类方法:基本方法和辅助方法。


(1)基本方法

① cy.get(selector)

该方法用来在 DOM 树中查找 selector 对应的 DOM 元素。比如:

it('测试get', () => {
  cy.get('#main1')
  cy.get('.btn')
  cy.get('li')
  cy.get('ul>[data-testid=li4]')
})

如果可以匹配多个元素,那么就会返回多个元素。(在这里建议适当回顾 CSS 选择器)

在这里需要补充说明,我们看到了上述代码中有一个 data-*的属性,为什么需要它,它又是用来做什么的?

首先,做 UI 自动化测试,很明显的,每个测试用例都会包含对元素的操作。因此健壮、可靠的元素定位策略就可以保障测试成功率的提高。而在开发过程中,作为开发人员,我们很清楚,有一部分元素的 ID 或 class 可能会动态生成,除此以外,在开发中,我们可能也会做出把元素 CSS 样式名改掉甚至去掉等操作。那这种情况下,测试必然失败。如果一个元素没有 class、id,或者说动态生成,作为测试又不能更改这些代码,那该如何获取元素,从而进行测试呢?

Cypress 就为此提供了一个特别的定位策略,让我们在面对这种情况下,无须过多担心因定位失败而导致的测试失败。它提供了 data-* 属性,就如上面的代码一样。data中包含了下面三个定位器:
data-cy
data-test
data-testid

它们都是 Cypress 专有的定位器,仅用来测试。data-* 属性和元素的行为或样式无关,意味着即使 CSS 样式或 JS 行为改变,也不会导致测试失败。

注意:在实际项目中,显然这个属性是需要自己将 data-* 属性加到元素中,意味着你得有权限修改代码。


② cy.find(selector)

该方法用来在 DOM 树中搜索已被定位到的元素的后代,并将匹配到的元素返回为一个新的 jQuery 对象,比如:

it('测试find - 正确写法', () => {
  cy.get("ul").find('#li1')
})
it('测试find - 错误写法', () => {
  cy.find('#li1')
})

③ cy.contains(content)

该方法用来获取包含指定文本的 DOM 元素,比如:

it('.contains(content)', () => {
  cy.contains('submit')
})
it('.contains(selector, content)', () => {
  cy.contains('ul>li', 'test1')
})
it('.contains(content) 正则', () => {
  cy.contains('/1$/')
})

总结一下:查找页面元素的基本方法
在这里插入图片描述


(2)辅助方法

单一的基础定位元素方法并不一定能满足复杂的场景,所以 Cypress 还提供了一些辅助方法,可以提高找到元素的准确性。对于具体的辅助方法就不在这里演示了,只不过需要注意,它们都需要在定位到元素后才能使用,和cy.get().find() 一样。比如:

cy.get('ul').children('#li1')
cy.get('ul').children()
cy.get('#li1').parents()
cy.get('ul>li').each(($li) => {
cy.log($li.text())
})
cy.get('ul>li').eq(1)

总结一下:查找页面元素的辅助方法
在这里插入图片描述
在这里插入图片描述


6、断言

当我们获取到了页面元素后,我们就可以使用断言。断言是测试用例的必要组成部分,没有断言就不知道测试用例的有效性。Cypress 的断言基于 Chai 断言库,并且增加了对 Sinon-Chai、Chai-jQuery 断言库的支持,其中就包括 BDD 和 TDD 格式的断言。

BDD 格式的断言:expect 、should
TDD 格式的断言:assert

常见的断言方式:

(1)长度 have.length

// 通过 get 获取到的元素是否有3个
cy.get('li.selected').should('have.length',3)

(2)类 not.have.class

// 通过 get 找到的表单中的 input 输入框是否没有拥有 disabled 的 class
cy.get('form').find('input').should('not.hava.class','disabled')

(3)值 have.value

// 找到的元素中,是否有值为 poloyy 的元素
cy.get('textarea').should('have.value','poloyy')

(4)文本内容 not.contain

// 找到的元素中的文本是否不含有 'click me'
cy.get('a').parent('span.help').should('not.contain','click me')

(5)针对元素是否可见 be.visible

// 是否有能看到的 button 元素
cy.get('button').should('be.visible')

(6)针对元素是否存在 not.exist

// 是否不存在一个 id 为 loading 的元素
cy.get('#loading').should('not.exist')

(7)针对元素状态 be.checked

// 有没有一个单选框,它的状态为被选择
cy.get(':radio').should('be.checked')

(8)针对 CSS hava.css

// 是否有一个包含指定 CSS 样式的元素
cy.get('.completed').should('have.css','text-decoration','line-through')

(9)针对回调函数
如果内建的断言没有满足需求,那么可以自己写断言函数,然后作为一个回调以参数的形式传给 .should()

cy.get('.div').should(($div) => {
	expect($div).to.have.length(1)
	const className = $div[0].className
	expect(className).to.match(/heading-/)
})

补充说明:重试

重试(Retry-ability)是 Cypress 的核心概念之一,有助于我们写出更加健壮的测试。比如,我们用断言cy.get(‘textarea’).should(‘have.value’,‘poloyy’)。此时我们考虑以下问题:

如果断言发生时,应用程序尚未更新DOM怎么办?
如果断言发生时,应用程序正在等待其后端响应,而导致页面暂无结果怎么办?
如果断言发生时,应用程序正在进行密集计算,而导致页面未及时更新怎么办?
上述情况在测试中经常会发生,这就会导致测试失败。

Cypress 解决上述问题就用到了重试:
(1)cy.get() 命令之后的断言通过,则该命令成功执行完成;
(2)cy.get() 命令之后的断言失败,则 cy.get() 命令会自动重新查询 web 应用程序的 DOM 树,然后 Cypress 将再次尝试对 cy.get() 返回的元素进行断言;
(3)如果断言仍然失败, cy.get() 仍然会重新查询 DOM 树…以此类推;
(4)直到断言成功或 cy.get() 命令超时。

除此以外,在日常测试中,有时候需要多重断言,即获取元素后跟多个断言。在多重断言中,Cypress 将按顺序进行断言,即当第一个断言通过后,会进行第二个断言,通过后进行第三个断言…以此类推。

当然,重试也是有条件的,并不是所有命令都会去不断重试。比如:当命令可能改变被测应用程序的状态时,该命令将不会重试(如: click())。Cypress 仅会重试那些查询 DOM 的命令: cy.get() 、 find() 、 contains() 等

补充:重试的超时时间默认是 4秒,对应的配置项是: defaultCommondTimeout ,如果想改重试的超时时间,在 cypress.json 文件改对应的字段值即可


7、点击事件

点击事件用法比较简单,依然是通过 get 获取到元素后,用 .click 的方式去触发。但其中有很多更深的内容,可参考文章:
https://www.cnblogs.com/poloyy/p/13066005.html
在这里插入图片描述


8、操作页面元素的命令

操作页面元素的命令依然是在获取到元素后,再进行操作。比如:

cy.get('input').type('输入')
cy.get('input').first().focus()
cy.get('input').eq(0).type('234').clear()
cy.get('form').submit()
cy.get('[type="radio"]').first().check()
cy.get('select').select('user')
cy.get('footer').scrollIntoView()
cy.get('a').trigger('mousedown')

具体总结如下:
在这里插入图片描述


9、其余命令参考书

通过以上内容,已经可以实现一个基本的测试用例:查找页面元素、操作页面元素、断言、触发事件。比如,现在可以去查看 Cypress 自动生成的简例中,查看简单的测试用例。如下面的第十部分内容。由于 Cypress 的相关命令众多,它还可以获取页面全局对象、操作浏览器、操作文件、发送HTTP请求、操作Cookie等等,所以剩下的命令在需要时将会去博客中按需查找用法:

https://www.cnblogs.com/poloyy/p/14031640.html


10、官方测试用例

通过对上述命令的简单了解和学习,针对目前 Cypress 自动生成的目录结构中的todo.spec.js 为例,对其中的基本用法再做总结:

// 测试套件 describe
describe('example to-do app', () => {

  // 钩子函数:所有测试用例都会使用
  beforeEach(() => {
    // Cypress 在每次测试中都会是从一张空白页面开始
    // 因此,我们必须告诉所有的测试,先用 cy.visit 去访问 Cypress 例子的网站
    // 由于我们希望在所有测试开始时,访问相同的 URL
    // 所以,我们将它包含在 beforeEach 函数中,以便在每个测试之前运行
    cy.visit('https://example.cypress.io/todo')
  })

  // 一条测试用例:展示 todolist 的两个默认项
  it('displays two todo items by default', () => {
    // 使用 cy.get 获取与 css 选择器匹配的所有元素
    // 随后使用 should 断言,去判断此处是否有两个默认项
    cy.get('.todo-list li').should('have.length', 2)

    // 更进一步的,我们可以使用 first 和 last 去单独获取第一个和最后一个匹配的元素
    // 随后使用 should 断言,去匹配里面是否有对应的文本
    cy.get('.todo-list li').first().should('have.text', 'Pay electric bill')
    cy.get('.todo-list li').last().should('have.text', 'Walk the dog')
  })

  // 一条测试用例:是否可以添加一个新的 todoitems 项
  it('can add new todo items', () => {
    // 创建一个变量,以便后续对它重用
    const newItem = 'Feed the cat'

    // 寻找到输入框的元素,通过 type 去将输入的内容写入
    // 再写入后,我们需要敲击 enter 才会提交这个输入
    cy.get('[data-test=new-todo]').type(`${newItem}{enter}`)

    // 现在新的内容已经生成,我们先用断言去判断此处是否有三个默认项
    // 因为这是新增的内容,这个内容会作为列表的最后一个元素存在
    // 注意:断言必须生成在一个元素上,
    // 而在这里用 last 获取到了最后的元素,所以这里可以嵌套断言
    cy.get('.todo-list li')
      .should('have.length', 3)
      .last()
      .should('have.text', newItem)
  })

  // 一条测试用例:是否可以检测每一项的 checkbox 状态
  it('can check off an item as completed', () => {
    // 除了使用 get 利用选择器获取元素外,contains 也可以获取元素
    // 这种方式就是寻找页面中存在的文本
    // 寻找到这个文本后,我们需要去找到它的父类 input 标签,从而调整 checkbox 状态
    // 所以在这里先用 parent 拿到当前文本的父类 input 标签
    // 随后在父类中,找到 checkbox 选择器,再使用 check 命令对其进行选中
    cy.contains('Pay electric bill')
      .parent()
      .find('input[type=checkbox]')
      .check()

    // 现在我们依然使用这种方式,寻找这个文本标签
    // 随后使用 parents 一直向上遍历,寻找 li 标签
    // 最后找到这个元素后,将它的类改为已完成状态
    cy.contains('Pay electric bill')
      .parents('li')
      .should('have.class', 'completed')
  })

  // context 是 describe 的别名,我们可以创建嵌套测试套件
  // 一条测试用例:与 checked 相关的测试
  context('with a checked task', () => {

    // 钩子函数
    beforeEach(() => {
      // 每个测试用例运行前,先把这个文本中的 checkbox 选中,用于后面的测试
      cy.contains('Pay electric bill')
        .parent()
        .find('input[type=checkbox]')
        .check()
    })

    // 测试用例:点击 Active 按钮,去除未完成任务
    it('can filter for uncompleted tasks', () => {
      // 寻找到拥有 Active 文本的标签,触发点击事件
      cy.contains('Active').click()

      // 为了检测是否成功,我们去判断 todolist 里是否只有一个 todoitems
      // 且它的值为 walk the dog
      cy.get('.todo-list li')
        .should('have.length', 1)
        .first()
        .should('have.text', 'Walk the dog')

      // 为了更好的测试,我们也可以检测一下,是否页面中不存在拥有这个文本的标签
      cy.contains('Pay electric bill').should('not.exist')
    })

    // 测试用例:点击 Completed 按钮,去除已完成任务
    it('can filter for completed tasks', () => {
      // 寻找到拥有 Completed 文本的标签,触发点击事件
      cy.contains('Completed').click()

      // 为了检测是否成功,我们去判断 todolist 里是否只有一个 todoitems
      // 且它的值为 Pay electric bill
      cy.get('.todo-list li')
        .should('have.length', 1)
        .first()
        .should('have.text', 'Pay electric bill')

      // 为了更好的测试,我们也可以检测一下,是否页面中不存在拥有这个文本的标签
      cy.contains('Walk the dog').should('not.exist')
      // 我们也可以使用这种方式
      cy.get('.todo-list li').should('not.have.text', 'Walk the dog')
    })
  })
})

Cypress 和项目相关的准备工作


1、Cypress 访问项目路径

在进入测试前,必不可少的就是先让 Cypress 能够链接上我们的项目,也就是首先先能够访问项目。而想要实现这一步,需要去 cypress.json 中进行设置。配置方法有以下三种:(不要忘记先运行自己的项目)


(1)修改环境变量

在之前的笔记中,有提到过 cypress.json 其中的配置项。其中,有一个配置项 env,我们可以根据它来设置访问路径:

{
  "env": {
    "url": "http://localhost:18082"
  }
}

此时我们想使用时:

describe('测试', () => {
  beforeEach(() => {
    cy.visit(Cypress.env('url'))
  })
  it('进入?', () => {
    cy.log('进入')
  })
})

效果:
在这里插入图片描述

但是这种方式并不是常规的解决方案,因为 Cypress 中本身有直接配置路径的配置项,我们将路径配在这里有点得不偿失。而且我们想要获取路径时,还需要通过 Cypress.env 写出来,很麻烦。对此,可以使用第二种方法。


(2)修改配置项 baseUrl

在 cypress.json 中,添加如下配置项:

{
  "baseUrl": "http://localhost:18082",
}

此时我们想使用时:

describe('测试', () => {
  beforeEach(() => {
    cy.visit('')
  })
  it('进入?', () => {
    cy.log('进入')
  })
})

需要注意的是:当我们配置了 baseUrl ,测试套件中的 cy.visit() 、 cy.request() 都会自动以 baseUrl 的值作为前缀。但是这并不代表我们就可以不用写 cy.visit(),或者里面可以为空。调用时,至少也要传个空字符串,如上例。并且,当我们需要访问某些网址或者发起接口请求时,在代码中就可以不用再指定请求的 host 或者 url 了。

效果:
在这里插入图片描述

但这个方法也有坏处:虽然我们现在 cy.visit() 中已经什么都不用写了,但是如果我们想要在不同的环境中,访问不同的路径该怎么办?手动去改 baseUrl 还是很麻烦。对此,可以使用第三种方法。


(3)启动项目时进行配置

这次我们不在 cypress.json 中进行配置,而是在 package.json 中进行配置。之前我们在 package.json 中的 scripts 中,添加过运行的命令。现在相关的配置项,依然设置在这个 scripts 中。我们要做的就是在 cypress open 的时候,直接为其配置不同开发环境下的 baseUrl 即可。那么不同开发环境的不同路径就可以在 package.json 中统一管理。具体来看:

"scripts": {
  "test:gui": "cypress open --config baseUrl=http://localhost:18082 --env mode=dev",
  "dev:gui": "cypress open --config baseUrl=http://172.18.193.237:9800/ --env mode=dev",
  "prod:gui": "",
  "dev:cli": "cypress run --config baseUrl=http://localhost:18082 --env mode=dev",
  "prod:cli": "",
  "open": "cypress open"
},

(test测试。dev开发。prod生产)

随后,我们使用 npm run test:gui 运行。
在这里插入图片描述

测试是否可行:(不要忘记去掉 cypress.json 中的 baseUrl 配置项)
在这里插入图片描述

这种方法和配置 baseUrl 的用法是一样的,只不过是在 npm 运行时,将这个配置项进行了一次配置,从而区分出了不同环境下的不同路径。在这段代码中,还有一些其他用法。

其中的 cypress run 它的作用就是用 cmd 命令行运行 cypress / integration 目录下的所有测试用例,并在运行完成后在控制台输出一个总结的报告。那么如果我们想看到所有测试的结果,比如:成功、失败的测试用例数量、运行时间等,那么就可以直接使用这种方式。
在这里插入图片描述

Cypress run 相关的更多内容可参考:
https://www.cnblogs.com/yoyoketang/p/12974805.html

而除了 --config 外,后面还有一个 --env,这就涉及到环境变量了。在这里的含义就是,将 cypress.json 中 env 中的 mode 设置为 dev。这些不同的环境变量,也有它自己的作用。


2、环境变量

环境变量就是根据环境的变化,变量会有不同的值。比如最常见的:开发环境、测试环境、生产环境的 URL 肯定不一样,我们可以根据不同的环境选择不同的环境变量。设置环境变量有以下几种方式。


(1)在 cypress.json 文件中设置

这是一种最常见的使用方式。写在 cypress.json 中的 env 配置中,在测试运行时,就使用 Cypress.env() 访问这些值。就比如在第一节使用 url 一样:

cy.visit(Cypress.env('url'))

当不同环境运行时,如果需要访问不同的数据值,我们只需要改环境变量即可了,而不用动到代码。改变的方式就可以采用第一节中使用的,在不同的运行环境下,通过 --env 去配置不同的mode,那么根据不同的 mode 就可以获取不同的访问值。比如:

it('进入?', () => {
  cy.log(Cypress.env('mode'))
})

在这里插入图片描述

又或者我们直接在 --env 后,添加我们想要增加的环境变量也可以,但是这样一来在这里添加的内容可能会比较多,麻烦。

这种用法会有一些问题:目前是通过 npm 时传递参数的方式,从而确保在 env 中区分出不同的环境变量,但是如果是团队开发,那么这些文件属于项目共有项,很容易出现冲突。也就是说,这种方法适用于在所有计算机上有相同的值。而为了解决这个问题,有了接下来的方法。


(2)创建一个 cypress.env.json 文件

在项目中是没有这个文件的,我们需要自己去创建 cypress.env.json 文件,在项目的根目录下(cypress.json 同级目录下)。它的作用是,每次运行时,Cypress 将会自动检查它,并且里面的值会覆盖 cypress.json 中重名的环境变量。这样一来第一种方案下的问题就解决了。此时,在团队开发时,如果将cypress.env.json 添加到.gitgnore文件中,那么文件中的值对于每个开发人员的计算机都是不同的,不会互相影响。

这种方法也会有问题:我们需要在项目中单独多处理一个新文件,而且也有可能会出现覆盖掉关键的同名环境变量的情况,在纠错时就很难发现了。 但没关系,只要注意到这些问题,我们依然可以采用这种方案。


(3)导出为 CYPRESS_*

针对第二个问题中,项目需要单独多处理一个新文件,Cypress 也提供了一种新解决方案:在计算机中,任何以 CYPRESS_ 或 cypress_ 开头的环境变量都会自动被 Cypress 识别出来,随后直接覆盖 cypress.json 和 cypress.env.json 文件中重名的环境变量。这样一来,相关文件完全由计算机自己持有。
在这里插入图片描述


(4)可以通过 test configuration 设置环境变量

当然,也还有一种最基本的方法,就是给测试用例或测试用例集单独设置环境变量,但是这样很没必要,因为它会覆盖其他方式设置的环境变量。

  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2021-08-21 15:46:10  更:2021-08-21 15:47:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/17 20:33:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码