当前位置: 首页 > news >正文

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');});
});

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 应用在网络摄像机领域中的国产音频ADC芯片
  • 二叉树详解(深度优先遍历、前序,中序,后序、广度优先遍历、二叉树所有节点的个数、叶节点的个数)
  • 漏洞复现-海康威视网络对讲广播系统远程命令执行漏洞(附漏洞检测脚本)
  • vue3 element plus el-table封装(二)
  • Spring Boot 自动配置功能介绍
  • STM32CubeMX教程11 RTC 实时时钟 - 入侵检测和时间戳
  • ES6之解构赋值详解
  • 跨进程通信 macOS XPC 创建实例
  • yolov5旋转目标检测-遥感图像检测-无人机旋转目标检测-附代码和原理
  • 面试算法:快速排序
  • 【AIGC-图片生成视频系列-4】DreamTuner:单张图像足以进行主题驱动生成
  • EST-100身份证社保卡签批屏按捺终端PC版web版本http协议接口文档,支持web网页开发对接使用
  • 制作一个可以离线安装的Visual Studio安装包
  • 【QT】qt各模块描述
  • windows2012 安装mysql5.7
  • [数据结构]链表的实现在PHP中
  • If…else
  • Nodejs和JavaWeb协助开发
  • node和express搭建代理服务器(源码)
  • open-falcon 开发笔记(一):从零开始搭建虚拟服务器和监测环境
  • PHP那些事儿
  • Sass 快速入门教程
  • webpack项目中使用grunt监听文件变动自动打包编译
  • 成为一名优秀的Developer的书单
  • 解决iview多表头动态更改列元素发生的错误
  • 解析 Webpack中import、require、按需加载的执行过程
  • 老板让我十分钟上手nx-admin
  • 试着探索高并发下的系统架构面貌
  • 写给高年级小学生看的《Bash 指南》
  • 在GitHub多个账号上使用不同的SSH的配置方法
  • 中文输入法与React文本输入框的问题与解决方案
  • ​​​​​​​开发面试“八股文”:助力还是阻力?
  • (Ruby)Ubuntu12.04安装Rails环境
  • (vue)页面文件上传获取:action地址
  • (九)信息融合方式简介
  • (三)Kafka 监控之 Streams 监控(Streams Monitoring)和其他
  • (十二)python网络爬虫(理论+实战)——实战:使用BeautfulSoup解析baidu热搜新闻数据
  • (图文详解)小程序AppID申请以及在Hbuilderx中运行
  • (限时免费)震惊!流落人间的haproxy宝典被找到了!一切玄妙尽在此处!
  • (续)使用Django搭建一个完整的项目(Centos7+Nginx)
  • (学习日记)2024.03.12:UCOSIII第十四节:时基列表
  • (学习总结16)C++模版2
  • .bat批处理(一):@echo off
  • .Net Attribute详解(上)-Attribute本质以及一个简单示例
  • .NET CORE 第一节 创建基本的 asp.net core
  • .net core webapi Startup 注入ConfigurePrimaryHttpMessageHandler
  • .Net Core 微服务之Consul(三)-KV存储分布式锁
  • .net core使用RPC方式进行高效的HTTP服务访问
  • .NET(C#、VB)APP开发——Smobiler平台控件介绍:Bluetooth组件
  • .net2005怎么读string形的xml,不是xml文件。
  • .NET命名规范和开发约定
  • .NET设计模式(11):组合模式(Composite Pattern)
  • [ vulhub漏洞复现篇 ] GhostScript 沙箱绕过(任意命令执行)漏洞CVE-2019-6116
  • []Telit UC864E 拨号上网
  • [AndroidStudio]_[初级]_[修改虚拟设备镜像文件的存放位置]