UI 自动化中的分层设计

以前的设计

在过去 UI 自动化测试领域有一个规范的设计模式是 page object 模式。 意思是测试用例不会直接定位页面元素, 而是把每一个页面封装成一个类。 在这个类中封装页面元素。 然后测试用例调用 page 类来操作页面元素完成测试用例。如下图:

以前的设计

在过去 UI 自动化测试领域有一个规范的设计模式是 page object 模式。 意思是测试用例不会直接定位页面元素, 而是把每一个页面封装成一个类。 在这个类中封装页面元素。 然后测试用例调用 page 类来操作页面元素完成测试用例。如下图:

但这个模式已经诞生了差不多 20 年了。 它是以当时的前端开发模式为基础进行规定的。 而 20 年间前端技术和研发模式已经发生了很大的变化,这个模式已经不再适用当前的 UI 自动化项目了。所以我在我的项目用将上面的模式做了一些改良

改良后的设计

组件层

当下前端框架都有组件库的概念。 目的是封装通用的页面元素来让各个页面统一调用。 避免了重复开发的问题并且保持风格统一, 比如我之前在写前端项目的时候也会封装组件库, 然后在各个页面调用组件库中的组件。 我拿我之前写的前端项目举例:

如上图中在一个前端项目中, 会专门有一个叫 component 的目录(第一张图),该目录里会封装常用的页面组件,比如 button,input,dropdown,link 等。 而每个组件都会编写独立的逻辑代码和 css 代码(第二张图)。 最后在页面中通过调用组件库的组件来完成页面逻辑(第三张图, 页面中调用了第二张图里展示的 LinkButton)。 所以我们在产品界面中才会发现很多控件长得都一样, 连属性都一样, 比如 class 里的值都是一样的。 这是因为他们其实是完完全全的同一个组件。 PS:在 CSS 中比较常用 class 来定位控件。 所以我们在控件中一般能看到各种 class 定义。 这就是现代前端项目的开发模式, 我们总能听到前端研发工程师们说的组件化,其实就是这个了。 这也是为什么我们会专门抽象出一层组件层的原因。 如果研发在迭代过程中修改了组件库, 那么会影响所有的页面。 一般这对 UI 自动化来说是一个很大的打击。 所以为了避免这种情况出现,同时为了简化页面定位成本。 所以 UI 自动化项目中也要对应的封装出一个组件层来专门做元素的定位和操作。 比如我之前曾经在产品中见过这样的情况, 之前我们的 button 都是下面这个样子的。

<button> 确定 </button>

但是突然研发修改了 button 组件库。 于是所有的 button 就变成了下面这个样子:

<button>
    <span> 确定 </span>
</button>

在修改之前一切很美好, 我们只需要用 bytext 方法或者用一个 xpath: //button[text()='确定'] 就能很方便的找到这个 button 并点击. 但某一天研发的组件库变了, button 不在有文案了, 而是在 button 里加了个 span 的子元素放置文案。 于是在 UI 自动化项目中以前所有页面的所有 button 定位和操作都挂了, 都需要改一遍。所以我们一般在 UI 自动化中通过增加一个组件层来解决这个问题。 如下图:

如上图, 在我们的测试代码中专门有一个名字叫 component 的目录, 里面根据控件的类型划分了很多文件, 每个文件里定义着这个类型的控件常用的定位和操作方式。 第二张图中我们看到的是 input 这个组件在产品中通用的逻辑。 比如拿 form_upload 这个控件来解释, 在产品中绝大部分上传文件的控件是由 input 组件来封装的。 点击上传操作其实触发的就是往一个属性 type=file 的 input 元素写入文件路径。 所以其实所有页面的上传操作都可以调用这个逻辑完成。 特别需要注意一点, 组件层不仅仅是封装元素的定位逻辑的, 也会封装一些常用操作。 还是拿上传控件来说, 用户在前端是要点击上传这个 button 后跳出一个文件选择框来完成上传操作的。 但是这个逻辑在 UI 自动化中是不可行的, 因为跳出这个文件选择框并不是浏览器的行为,而是当前操作系统的行为。 所以这个框实际上不受 webdriver 控制,并且不同的操作系统下这个框的样子也是不一样的。 所以在 UI 自动化中,我们只能通过给这个 input 元素直接写入上传的文件路径来触发文件操作。 但是这个 input 元素的 css 代码中设置了 style.display=none, 把这个 input 元素设置为了隐藏, 而 webdriver 是没办法与隐藏元素交互的。 所以我们需要先通过嵌入一段 js 代码, 把这个 input 修改成可见元素才能完成剩下的操作。 通过这个案例我想说明在组件层除了封装元素的定位方式外, 也会封装元素的操作方式。

原则上,我们所有的页面元素的交互都需要通过调用组件层的函数来完成, 一个是加快元素定位的速度 -- 调用者不再需要自己定位了, 只需要调用组件层的方法,传递参数即可。 第二个是通过统一调用, 一旦后续前端组件库发生变化,导致元素定位方式也要改变。 我们只需要修改组件层非常少量的代码即可。 而不是研发动了一行代码, 测试项目这边需要成片的逻辑修改。

页面层

页面层与老式的 page object 模式中的页面层基本类似。 一个页面封装成一个 class, 在这个 class 里定义所有的元素和对应的操作。 只不过这类对元素的定位工作基本都是通过调用组件层的能力来完成的。 如下图:


可以看到,一个页面上的所有元素都是定义在这个 class 里面的。 并且这些元素的定位都是通过组件层的方法来完成的。 我们在文件开头就会引入这些组件库来帮助页面层来完成元素的定位于操作。 同时建议页面层文件不仅仅是封装单个元素的定位, 也可以封装页面里常用的操作。 我们推荐这种封装方式, 我们应该尽量避免在 case 中直接调用页面元素操作。 原因有二

  • 代码复用, 大量 case 其实都需要调用相同的逻辑,封装成可复用的代码可以减少 case 编写成本
  • 当页面元素出现变化,比如增删元素的时候。 可只修改封装的逻辑, 而不必大量修改 case。

组件层封装基本控件,应对前端组件库的变化, 而页面层就是对产品界面进行封装, 应对的是页面逻辑发生的变动

业务逻辑层

在我们的代码里, 每个模块都有 service 文件, 这个文件就是封装的业务逻辑的文件。 我们在页面层上封装的逻辑都是单页面逻辑。 而在测试中我们往往要执行一个很复杂的业务流程。 为了执行这样一个业务流程我们跳转了很多个页面。 所以我们有必要单独封装这样一层来把业务逻辑进行封装。 这里需要提一下, 业务逻辑层相当于页面层的上层封装。 封装了完成一个业务逻辑的所有操作,比如我们假设创建一个工作流, 需要先填写基本配置, 然后跳转到高级配置页面继续填写, 填写玩后点击确定显示创建成功, 到了这里还没结束,还需要等待这个工作流程执行到某个状态,比如运行成功状态。 这里面需要跳转多个页面,甚至还需要给定一个超时时间并轮询工作流程的状态。 为什么要封装这么一层呢, 因为必然有非常多的 case 去完成这样一个流程。

需要注意的是, 我们每个模块都需要封装自己的业务逻辑层。 因为一个产品里必然有非常多的模块并且这些模块之间是有依赖关系的。 比如我在之前讲大数据的时候介绍过, 一个大数据平台的产品中做什么事都需要先把外部数据源中的数据同步到本系统里对吧, 所以数据中心的测试人员就的把自己模块的业务逻辑封装一下给其他模块的人用。 同样的,模型中心模块的人要测试得先有个模型对吧, 那用来建模的建模中心就得把自己的业务逻辑封装好了给其他人用。 在 UI 自动化中往往就是这样的,各个模块之间需要互相配合,互相调用。 因为就是有很多 case 是横跨多个模块,链路非常长非常复杂的。

用例层

用例层就没啥好说的, 就是写 case 而已。 只不过在我的这个设计里, 用例层很轻, 大部分逻辑都已经被上面的 3 层做完了。 用例层大多数时候再调用业务逻辑层, 少数情况调用页面层。 所以 case 层很轻,代码很少。 没什么可以特别强调的。

总结

就写到这吧, 最近又开始写 UI 自动化所以有些感受, 组织了一篇帖子跟大家探讨一下。

更多内容欢迎来到我的知识星球:
 

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

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

相关文章

Linuxftp服务001匿名登入

在Linux系统中搭建FTP&#xff08;File Transfer Protocol&#xff09;服务&#xff0c;可以让用户通过网络在服务器与其他客户端之间传输文件。它有几种登入模式&#xff0c;今天我们讲一下匿名登入。 操作系统 CentOS Stream9 操作步骤 首先我们先下载ftp [rootlocalhost…

刷爆leetcode第八期

题目一 设计循环队列 题目分析 这里直接看图 我们发现这里要求我们设计一个循环队列 这要怎么设计呢&#xff1f; 还是一样 我们先画图 我们首先假设只能储存四个数字 同学们看这张图能观察到什么呢&#xff1f; 是不是可以得到front 和 rear相等的时候整个队列为空 这里…

【微机原理及接口技术】中断系统

【微机原理及接口技术】中断系统 文章目录 【微机原理及接口技术】中断系统前言一、中断概述中断的基本概念中断处理过程 二、8086/8088中断系统中断类型中断响应过程中断向量表内部中断服务程序 总结 前言 本篇文章我们会讲到中断的概述&#xff0c;8086/8088中断系统。 一、…

Mysql疑难报错排查 - Field ‘XXX‘ doesn‘t have a default value

项目场景&#xff1a; 数据库环境 &#xff1a;mysql8; 工程使用&#xff1a;MyBatisPlus 表情况&#xff1a; 问题描述 某一个插入语句使用了 MyBatisPlus 的 save 方法&#xff0c;因为end_time1 end_time2都并没有值&#xff0c;所以在MyBatisPlus默认情况下&#xff0c;…

SQL优化系列-快速学会分析SQL执行效率(下)

1 show profile 分析慢查询 有时需要确定 SQL 到底慢在哪个环节&#xff0c;此时 explain 可能不好确定。在 MySQL 数据库中&#xff0c;通过 profile&#xff0c;能够更清楚地了解 SQL 执行过程的资源使用情况&#xff0c;能让我们知道到底慢在哪个环节。 知识扩展&#xff1…

强化用户登录接口:解决登录接口被攻击导致掉线卡顿!

一、引言 用户登录接口是任何Web应用的核心部分&#xff0c;它负责身份验证和授权流程。然而&#xff0c;这些接口也常常成为黑客攻击的目标&#xff0c;尤其是当涉及到动态请求处理时。动态请求通常指的是根据用户输入生成的请求&#xff0c;这为诸如SQL注入、XSS攻击和CSRF攻…

华为 2024 届实习校园招聘-硬件通⽤(大部分硬件技术工程师岗位适用)/单板开发——第四套

华为 2024 届实习校园招聘-硬件通⽤&#xff08;大部分硬件技术工程师岗位适用&#xff09;/单板开发——第四套 部分题目分享&#xff0c;完整版带答案(有答案和解析&#xff0c;答案非官方&#xff0c;未仔细校正&#xff0c;仅供参考&#xff09;&#xff08;共12套&#x…

Unity Vuforia

首先在unity2019版本里可以在windows->PackageManager里搜Vuforia EngineAR; &#xff08;unity2021版本里搜不到&#xff09; 在官网注册账号&#xff1a; 添加识别图等&#xff1b; 将导出的unitypackage包导入unity中。 unity里导入package之后&#xff0c;新建场景&am…

【CentOS 7】挑战探索:在CentOS 7上实现Python 3.9的完美部署指南

【CentOS 7】挑战探索&#xff1a;在CentOS 7上实现Python 3.9的完美部署指南 大家好 我是寸铁&#x1f44a; 总结了一篇【CentOS 7】挑战探索&#xff1a;在CentOS 7上实现Python 3.9的完美部署指南详细步骤✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 此篇教程只适用于p…

HarmonyOS(二十四)——Harmonyos通用事件之触摸事件

1.触摸事件。 触摸事件是HarmonyOS通用事件的一种事件之一&#xff0c;当手指在组件上按下、滑动、抬起时触发。 名称是否冒泡功能描述onTouch(event: (event?: TouchEvent) > void)是手指触摸动作触发该回调&#xff0c;event返回值见下面TouchEvent介绍。 2. TouchEve…

Ubuntu下安装和配置Redis

目录 1、更新软件包 2、安装Redis 3、启动 Redis临时服务 4、测试Redis服务 5、配置redis服务 6、Redis服务控制命令 1、更新软件包 执行sudo apt-get update更新软件包 sudo apt-get update2、安装Redis 执行sudo apt-get install redis-server 安装命令 sudo apt i…

Apple - Image I/O Programming Guide

翻译自&#xff1a;Image I/O Programming Guide&#xff08;更新时间&#xff1a;2016-09-13 https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/ImageIOGuide/imageio_intro/ikpg_intro.html#//apple_ref/doc/uid/TP40005462 文章目录 …

docker网络详解

1. 网络模式 1.1 网络结构 当安装Docker以后&#xff0c;会自动创建三个网络。可以使用docker network ls命令列出这些网络。 $ docker network ls NETWORK ID NAME DRIVER SCOPE 440aefe8afa3 bridge bridge local aa8d6325580f host host …

RAG检索增强生成(1)-大语言模型的外挂数据库

Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks Lewis P, Perez E, Piktus A, et al. Retrieval-augmented generation for knowledge-intensive nlp tasks[J]. Advances in Neural Information Processing Systems, 2020, 33: 9459-9474. RAG结合了信息检…

linux网络 dns域名解析

目录 DNS 域名体系结构 如何实现域名解析 正向解析 反向解析 主从服务器解析 bond 网卡 DNS 是域名系统的简称 域名和ip地址之间的映射关系 互联网中 IP地址是通信的唯一标识 逻辑地址 访问网站 域名 IP地址不好记 域名朗朗上口 好记 域名解析的目的就是为了实现 访…

七天进阶elasticsearch[one]

elasticSearch 概述 Elasticsearch是一个近实时的搜索平台。这意味着&#xff0c;从索引一个文档直到这个文档能够被搜索到有一个很小的延迟&#xff08;通常是一秒&#xff09; 集群 一个集群就是由一个或多个节点组织在一起&#xff0c; 它们共同持有你全部的数据&#x…

代码签名证书:软件安全的守护神

在数字化日益普及的今天&#xff0c;软件安全问题愈发受到人们的关注。而在这其中&#xff0c;一个常被提及但可能不为大众所熟知的名词——“代码签名证书”&#xff0c;实际上在软件安全领域扮演着举足轻重的角色。今天&#xff0c;我们就来聊聊代码签名证书对软件安全到底有…

kali扩容

通过wmware虚拟机–>设置–>添加40G容量的硬盘。 ──(root㉿kali)-[~/桌面] fdisk -lDisk /dev/sda: 40 GiB, 42949672960 bytes, 83886080 sectors …

【关于傅里叶变换的一系列问题】

1. 为什么频率分辨率是 f s N \frac{f_s}{N} Nfs​​&#xff1f; 因为采样率 f s {f_s} fs​ 决定了最大频率范围&#xff08;奈奎斯特频率&#xff09;。时域信号长度 &#x1d441;决定了频域中的离散点数。DFT对长度为 &#x1d441;的时域信号进行变换&#xff0c;得到…

C++的类和new和delete和菱形继承机制

文章目录 参考虚函数使用虚函数的class结构相关实现源码IDA反编译子类虚表和父类虚表调用函数菱形继承 参考 https://showlinkroom.me/2017/08/21/C-%E9%80%86%E5%90%91%E5%88%86%E6%9E%90/ https://www.cnblogs.com/bonelee/p/17299985.html https://xz.aliyun.com/t/5242?t…