Cypress安装与使用教程(3)—— 软测大玩家

在这里插入图片描述

 
 

在这里插入图片描述
😏作者简介:博主是一位测试管理者,同时也是一名对外企业兼职讲师。
📡主页地址:【Austin_zhai】
🙆目的与景愿:旨在于能帮助更多的测试行业人员提升软硬技能,分享行业相关最新信息。
💎声明:博主日常工作较为繁忙,文章会不定期更新,各类行业或职场问题欢迎大家私信,有空必回。

在这里插入图片描述

 
 

阅读目录

  • 1. 接上回
  • 2. 自定义命令
    • 2.1 参数传递
    • 2.2 链式调用
    • 2.3 自定义断言
    • 2.4 处理异步操作
    • 2.5 Cypress对象
  • 3. 注意点
    • 3.1 关于脚本业务上下文
    • 3.2 抽象的程度

1. 接上回

在这里插入图片描述
  上一篇我们介绍了一些Cypress中的一些高频使用技巧,那么今天就由博主我继续来为大家带来关于Cypress的一些高阶技巧。

 
 

2. 自定义命令

在这里插入图片描述
  在Cypress中,自定义命令是一个强大的辅助功能,说直白点就是它允许你将重复使用的代码片段抽象成可重用的命令。而通过这些自定义的命令,我们可以让我们的自动化测试脚本更加的趋于模块化,可想而知的是,模块化的脚本其自身的可维护性、复用性和可阅读性就会更上一个台阶。

  要使用自定义命令,我们就需要在support/commands.js中建立自己的命令。比如我们需要将登录这个业务动作进行抽象,那就先编写一段登录的相关业务代码。

我们写一个十分简单的登录操作,语法如下,可以看到整个的业务代码十分的简单,只需要将用户名和密码进行传参即可。

Cypress.Commands.add('login', (username, password) => {
  cy.visit('/login');
  cy.get('#username').type(username);
  cy.get('#password').type(password);
  cy.get('button[type="submit"]').click();
});

  那么我们在commands.js中将这段业务代码添加完成后,在实际的测试脚本中就可以直接对其进行使用。
使用起来是不是很方便,因为其本身就是将业务方法继续抽象,所以直接调用其方法名就可以达到登录代码同样的效果。

describe('login_test', () => {
  it('should log in successfully', () => {
    cy.login('your_username', 'your_password');
  });
});

 

2.1 参数传递

  我们在定义业务方法的时候传参不仅仅可以传一些基础的业务参数,还可以在此基础上根据自己的业务场景来定义一些比较灵活的参数类别。比如我们在对特定元素进行业务操作时,我们可以统一的定义一个操作类或方法,来对此进行特定的传参,类似于selenium中find_elelment方法。

  我们先在commands.js中定义,这里我们要传递的参数是一个元素选择器。这样我们就可以灵活的在页面上选择到任何一个能捕捉到的元素。

Cypress.Commands.add('clickAndVerify', { prevSubject: 'element' }, (element, text) => {
  cy.wrap(element).click();
  cy.contains(text);
});

  使用的时候只需要直接调用即可。

cy.get('.my-button').clickAndVerify('Clicked Button Text');

 

2.2 链式调用

  自定义命令毫无意外的也支持了链式写法,无疑这让我们在设计脚本的过程中可以更加灵活的应对各类复杂业务场景。

  同样的现在commands.js中定义,这里我们在返回get的时候进行了链式调用。

Cypress.Commands.add('login', (username, password) => {
  cy.visit('/login');
  cy.get('#username').type(username);
  cy.get('#password').type(password);
  cy.get('button[type="submit"]').click();
  return cy.get('.user-dashboard'); 
});

  使用的时候只需要直接调用即可。

cy.login('your_username', 'your_password').should('be.visible');

 

2.3 自定义断言

  同样的,既然可以进行抽象,我们也完全可以将断言的操作加进自定义命令,以验证特定的状态或条件,包括一些特殊的验证逻辑。

  commands.js中定义,断言元素存在切包含text。

Cypress.Commands.add('shouldBeVisibleAndContain', { prevSubject: 'element' }, (element, text) => {
  cy.wrap(element).should('be.visible').and('contain', text);
});

  直接调用方法即可对元素进行断言。

cy.get('.my-element').shouldBeVisibleAndContain('Expected Text');

 

2.4 处理异步操作

  对于上一篇末尾处说到的异步操作处理,同样可以在自定义命令中进行抽象,其实在被测对象中异步操作是很常见的,比如等待某个条件成立后再继续执行后续的操作,类似的这种场景我们都可以在自定义命令中继续抽象和服用,以优化脚本的整体运行效率和维护性。

  在commands.js中定义,等待特定的条件后再执行后续的操作。

Cypress.Commands.add('waitForApiResponse', () => {
  cy.intercept('GET', '/api/data').as('apiCall');
  cy.wait('@apiCall');
});

  调用,不再赘述。

cy.waitForApiResponse();

 

2.5 Cypress对象

  除了以上说的这些方法外,我们还可以将一些元素和值包装成Cypress对象,这样做的作用就是让这些抽象后的对象可以在自定义命令中使用更多的Cypress自带命令。

  在commands.js中定义,我们使用cy.wrap()将对象包装成Cypress对象,使用自带的日志命令。

Cypress.Commands.add('logAndDebug', (subject) => {
  cy.wrap(subject).debug().log('Subject:', subject);
});

  调用,不再赘述。

cy.get('.my-element').logAndDebug();

 
 

3. 注意点

在这里插入图片描述
  我们在使用自定义命令的同时也需要注意一些特殊的情况与场景。

 

3.1 关于脚本业务上下文

  在自定义命令中,当然也存在着上下文的关系,我们要确保了解Cypress中命令的上下文,其中thisprevSubject 是特别觉有代表性的关键字。它们其实是允许你在自定义命令中引用和操作前一个命令的主体,就this这个来说,它在自定义命令中用于引用当前命令的上下文,对于一般的命令,它指向cy对象;对于一些带有{ prevSubject: 'element' }选项的命令,this则会指向前一个命令的主体,这个是需要大家注意的。

  下面我们来举两个例子:
  首先我们来看普通命令中的this,这里的this就是指向cy对象的。

Cypress.Commands.add('customCommand', function () {
  cy.log(this); 
});

  调用

cy.customCommand();

  而对面带有{ prevSubject: 'element' }的方法时,这里的this就像我之前说的那样,指向的是前一个命令的主体。简单点来说this指向前一个命令的subject,而cy.log(subject)里的就是前一个命令的主体。

Cypress.Commands.add('customCommandWithSubject', { prevSubject: 'element' }, function (subject) {
  cy.log(this); 
  cy.log(subject); 
});

  调用

cy.get('.my-element').customCommandWithSubject();

 

  prevSubject 的用作为告诉cypress你的自定义命令期望前一个命令的主体作为传参,一般在多个自定义命令中共享同一个元素的场景中会频繁使用到。

  同理,这里我们对前一个命令的主体进行点击操作,所以使用prevSubject 来达到我们所想要的效果。

Cypress.Commands.add('customCommandWithSubject', { prevSubject: 'element' }, function (subject) {
  cy.wrap(subject).click(); 
});

  调用

cy.get('.my-element').customCommandWithSubject();

 

3.2 抽象的程度

  虽然在自定义命令中我们需要对要定义的方法进行抽象,但往往会有些同学在设计的过程中什么都想要,从而导致自己的自定义命令变得过度抽象,这些代码的可读性一般都比较差而且维护起来难度较大,无法适应被测对象界面中的需求更改与样式变更。

  这里我们就举一个过度抽象的例子,让大家了解适度和过度抽象的区别。

  我们先来看一下过度抽象的自定义命令,这里虽然方法中提供了一个登录的基本步骤,但它的步骤过于具体,这样会导致在测试用例中要添加其他的测试逻辑变得困难,本身自定义命令的本质就是用来大量复用的,这样就变得本末倒置了。所以这样的抽象程度限制了自定义命令的灵活性,使得它本身的价值变得可有可无。

Cypress.Commands.add('login', (username, password) => {
  cy.visit('/login');
  cy.get('#username').type(username);
  cy.get('#password').type(password);
  cy.get('button[type="submit"]').click();
  cy.get('.user-dashboard').should('be.visible');
});

  调用

describe('Login Test', () => {
  it('should log in successfully', () => {
    cy.login('testuser', 'password123');
  });
});

  那么接下来我们看一下什么是适度抽象的自定义命令,下面这段乍一看似乎与上面的没什么很大的区别,其实则不然。在这其中我们只保留的基本的登录操作,不进行过多的细化操作,说人话就是我们只把共通与大框架的部分保留了下来,一些根据业务不同而扩展或特定的操作则被丢弃掉了。这样我们就可以在测试用例中添加更多的具体步骤来适应各类业务测试场景的需求。

Cypress.Commands.add('basicLogin', (username, password) => {
  cy.visit('/login');
  cy.get('#username').type(username);
  cy.get('#password').type(password);
  cy.get('button[type="submit"]').click();
});

  调用

describe('Login Test', () => {
  it('should log in successfully', () => {
    cy.basicLogin('testuser', 'password123');
    cy.get('.user-dashboard').should('be.visible');
  });
});

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/285875.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

计算商场优惠

#include<stdio.h> #include<string.h> #include<math.h> double amount(double list[], int n, double min) {int i;double sum 0, cheap list[0];for (i 0; i < n; i){sum sum list[i];if (list[i] < cheap) //找出最小的cheap list[i];}if (n…

Rust赋值语句和数字类型

赋值语句 在Rust中&#xff0c;使用let关键字定义变量。格式是let 变量名:变量类型 变量值;&#xff0c;下边是个例子&#xff1a; let age:i32 18;这就是定义一个有符号32位的数字变量age&#xff0c;而其中的值是18。 而在C语言定义变量的语句格式是类型 变量名 变量值。…

Tinker 环境下数据表的用法

如果我们要自己手动创建一个模型文件&#xff0c;最简单的方式是通过 make:model 来创建。 php artisan make:model Article 删除模型文件 rm app/Models/Article.php 创建模型的同时顺便创建数据库迁移 php artisan make:model Article -m Eloquent 表命名约定 在该文件中&am…

【软件工程】设计概念

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; 软件工程 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 软件工程中的设计概念 概念&#xff1a; 结语 我的其他博客 前言 在数字时代的浪潮中&#xff0c;软件工程设计成为塑造创新…

钡铼案例 污水处理远程监控系统的应用介绍

背景 这几年以来&#xff0c;随着国家对环保方面的重视&#xff0c;各地纷纷建立了自己的污水处理站。如何才能保护水资源让其循环利用达到节能减排&#xff0c;是目前急需解决的&#xff0c;正是污水处理项目对水资源的改善以及人民生活水平的提高有着重大的意义。 污水处理…

AC——对HTTPS数据进行行为审计时的解密方式

目录 SSL中间人解密 客户端代理解密&#xff08;准入插件解密&#xff09; 深信服的AC提供两种SSL解密技术用于对https行为进行解密 中间人解密和准入插件解密 SSL中间人解密 解密工作原理 当内网PC端发起SSL连接请求的时候&#xff0c;AC会以代理服务器的身份&#xff0…

vba抓取网页数据

哈喽&#xff0c;哈喽&#xff0c;大家好&#xff01;大家2024发大财啦&#xff01; 不知道&#xff0c;平时大家爱不爱看电影呢&#xff1f;从今年的贺岁档的拍片来看&#xff0c;今年的电影还挺多&#xff0c;而且国产优秀电影居多&#xff0c;元旦假期期间我也去看了部喜剧…

【数据库原理】(4)数据模型介绍

在数据库中&#xff0c;数据不仅包含数据本身的内容&#xff0c;还包括数据之间的关系。这是因为计算机无法直接处理现实世界中的具体事物&#xff0c;因此必须将这些事物抽象成数据模型&#xff0c;以便计算机处理。 数据处理的三个领域 数据从现实世界到数据库里的具体表示…

【C++学习】:命名空间、输入输出和缺省参数全面解析

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; C入门到进阶 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一. 命名空间1.1 为什么需要命名空间&#xff1f;1.2 命名空间的定义1.3 命名空间特性1…

3个值得推荐的WPF UI组件库

WPF介绍 WPF 是一个强大的桌面应用程序框架&#xff0c;用于构建具有丰富用户界面的 Windows 应用。它提供了灵活的布局、数据绑定、样式和模板、动画效果等功能&#xff0c;让开发者可以创建出吸引人且交互性强的应用程序。 HandyControl HandyControl是一套WPF控件库&…

图像分割实战-系列教程9:U2NET显著性检测实战1

&#x1f341;&#x1f341;&#x1f341;图像分割实战-系列教程 总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 U2NET显著性检测实战1 1、任务概述

如何本地快速部署Apache服务器并使用内网穿透工具实现公网访问内网服务

文章目录 前言1.Apache服务安装配置1.1 进入官网下载安装包1.2 Apache服务配置 2.安装cpolar内网穿透2.1 注册cpolar账号2.2 下载cpolar客户端 3. 获取远程桌面公网地址3.1 登录cpolar web ui管理界面3.2 创建公网地址 4. 固定公网地址 前言 Apache作为全球使用较高的Web服务器…

深度学习|2.4 梯度下降

如上图&#xff0c; J ( w , b ) J(w,b) J(w,b)是由w和b两个参数共同控制的损失函数&#xff0c;损失是不好的东西&#xff0c;所以应该求取合适的w和b使得损失最小化。 为了简单考虑&#xff0c;可以先忽略参数b。 斜率可以理解成在朝着x正方向移动单位距离所形成的损失值的变…

【Linux驱动】设备树模型的LED驱动 | 查询方式的按键驱动

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《Linux驱动》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 &#x1f36e;设备树模型的LED驱动&#x1f369;设备树文件&#x1f369;驱动程序 &#x1…

【数据结构】树的遍历

树的遍历 前序遍历 前序遍历是按照根节点->左子树->右子树的顺序进行遍历 图片来源维基百科深度优先遍历&#xff08;前序遍历&#xff09;: F, B, A, D, C, E, G, I, H. 代码实现 递归 # class TreeNode: # def __init__(self, x): # self.val x # …

[笔记] GICv3/v4 ITS 与 LPI

0. 写在前面 由于移植一个 pcie 设备驱动时&#xff0c;需要处理该 pcie 设备的 msi 中断(message signaled interrup)。 在 ARM 中&#xff0c; ARM 建议 msi 中断实现方式为&#xff1a; pcie 设备往 cpu 的一段特殊内存&#xff08;寄存器&#xff09;写某一个值&#xff0…

浅析xxl-obj分布式任务调度平台RCE漏洞

文章目录 前言本地环境搭建1、初始化数据库2、搭建调度中心3、搭建出执行器 XXL-JOB漏洞1、后台弱口令->RCE2、未授权API->RCE3、默认accessToken4、CVE-2022-361575、SSRF漏洞->RCE 总结 前言 在日常开发中&#xff0c;经常会用定时任务执行某些不紧急又非常重要的事…

c# 捕获全部线程的异常 试验

1.概要 捕获全部线程的异常 试验&#xff0c;最终结果task的异常没有找到捕获方法 2.代码 2.1.试验1 2.1.1 试验结果 2.2 代码 2.2.1主程序代码 using NLog; using System; using System.Threading; using System.Windows.Forms;namespace 异常监控 {static class Program…

【C#】知识点实践序列之Lock简单解决并发引起数据重复问题

欢迎来到《小5讲堂之知识点实践序列》文章&#xff0c;大家好&#xff0c;我是全栈小5。 这是2023年第3篇文章&#xff0c;此篇文章是C#知识点实践序列文章&#xff0c;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 本篇在Lock锁定代码块基…

主浏览器优化之路2——Edge浏览器的卸载与旧版本的重新安装

Edge浏览器的卸载与旧版本的重新安装 引言开整寻找最年轻的她开始卸载原本的Edge工具下载后新版本的安装 结尾 引言 &#xff08;这个前奏有点长&#xff0c;但是其中有一些我的思考顿悟与标题的由来&#xff0c;望耐心&#xff09; 我在思考这个系列的时候 最让我陷入困得是…