乐趣区

关于ui:得物技术分布式-UI-自动化实践

前言

提起 UI 自动化测试,总是会有人抛出很多疑难:

  1. UI 自动化能带来什么价值吗?还是在浪费时间?
  2. UI 自动化测试在整个测试流程中表演什么样的角色?
  3. 有编写 UI 自动化测试的工夫,我早就实现业务测试了,我为什么还要编写自动化测试的 case 呢?
  4. 针对于 UI 界面常常变动的业务场景,编写和保护自动化 Case 几乎太难了,怎么样能力解决这些问题呢?

……

明天小编就在这里跟大家分享下,本人对 UI 自动化测试的了解以及我司品质平台正在搭建的分布式平台 DuLab 是怎么实现批量运行 UI 自动化测试 Case 的。

为什么要做 UI 自动化?

随着不停的版本迭代,软件新增性能变的越来越多,对测试资源的需要也变得越来越大,执行人工测试的工夫越来越长。对于人工测试的依赖开始变得辣手,因而大家开始寻找解决方案,UI 自动化也应运而生。

人工测试的弊病

  • 人工回归测试须要破费很长时间能力实现,很小的提早就会让公布面临危险。
  • 公布节奏受到人工回归测试的限度。两天以上的人工回归测试意味着最好的状况下可能一个月公布两次。而且,开发者须要一次性公布所有货色。要么全副公布,要么什么都公布不了,因为须要将所有货色一起测试。

UI 自动化测试的长处

  • 解放了测试团队针对长期的和探索性案例的测试工夫;
  • 能够一边开发一边进行回归测试,缩小等待时间;
  • 可重复性应用,疾速进行回归测试;
  • 更好的利用资源(周未 / 早晨的资源闲暇时段)。

UI 自动化的特点

UI 即 User Interface(用户界面)的简称,UI 自动化做的事件就是模仿用户行为进行操作,实现对用户界面的测试。这也就从实质上限度了它的应用场景:

  • 软件需要变动不频繁
  • 产品更新保护周期长
  • 比拟频繁的回归测试
  • 自动化测试脚本可重复使用

所以在你开始之前,最好意识分明哪些业务场景是能够自动化的~

预期成果

针对我司的业务现状,确定好预期成果。

  • 兼容性测试:针对市场上罕用机型与零碎版本,进行下载安装应用,以发现兼容性故障,进而修复。
  • 埋点测试:校验埋点数据是否失常上报,有无漏报,错报,多报。
  • 回归测试:版本迭代中,进行回归测试保障代码改变不会导致其余场景产生故障。
  • 测试阶段性能收集:在测试阶段为自动化 case 指定优先级,依照优先级运行自动化 case,提供更多的性能数据。

思路

与接口自动化测试思路雷同,咱们在进行 UI 自动化测试时,每个 Case 都是一个独自的 TestCase,咱们将所有须要执行的 case 放在同一个 TestSuit 中,批量执行并生成聚合报告。

难点

  • 不同于接口自动化,单个客户端设施某个时刻仅反对运行一个自动化 Case;
  • 受制于电脑性能,无奈在繁多电脑设备上同时管制数十台挪动设施;
  • 随着版本迭代,局部 Case 仅实用于某些 APP 版本,需限度版本范畴;
  • 无奈省略前置步骤,比方说想要对某个页面进行 UI 自动化,无奈间接进入该页面,要从启动 APP 开始,抉择前置门路能力进入指定页面;
  • 雷同场景下数据可能会发生变化,使得校验规定无奈对立;
  • 不同账号下,数据不同,可能会导致很多场景无奈测试;
  • 对各种零碎各种型号的挪动设施,进行近程管制;
  • 如何在 UI 自动化的过程中校验埋点数据;
  • 大量的 AB 试验,如何切换环境进行测试;
  • APP 安装包的治理,如何抉择安装包进行笼罩装置.
  • ……

架构

上面是小编本人从点到面一步步的思考历程,从根本的挪动设施远程管理,case 编写到 case 的保护,再到 lab 平台的搭建:

支流工具调研

目前市面上有很多成熟的 UI 自动化工具,如 appium,airtest,Sikuli 等等,它们提供了十分便捷的录制服务,咱们只须要在 idea 上拖拖拽拽,马上就能够生成一个简略的 UI 自动化脚本,且咱们只须要将这些工具封装的工具库部署在咱们的电脑上就能够屡次运行咱们编写的 case 了。

这里咱们将离开分析进行 UI 自动化用到的录制器和执行器的原理:

case 执行的原理

解读其源码咱们发现这些工具其实底层的实现原理都基本相同,外围即为:对挪动设施的近程管制,并将控制指令封装为可读通用的语法。

其实咱们日常应用手机时,手机零碎就是通过咱们点击的屏幕坐标,从最上层的 view 顺次向下遍历,直到找到该坐标地位下能够响应用户行为的 UI 控件,执行对应的响应代码。

然而咱们在编写 case 时,如果 case 中记录的全是在某个坐标下对应的操作行为的话,就会特地的艰涩难懂,且针对不同屏幕尺寸的设施也齐全不通用,这显然是行不通的。

实在的用户行为其实无非就是,点击了某个按钮,滑动了某个页面等等,主体其实就是 UI 控件,咱们在编写 case 时也是一样的,我心愿的是对某个 UI 控件进行操作,那么其实在执行 case 时,咱们齐全能够获取该 UI 控件在以后屏幕中的地位,再去调用底层的控制指令进行操作。

case 录制的原理

其实 case 录制的原理就是上述执行原理的逆向思维,咱们能够在挪动设施上开启 server 服务,将挪动设施的屏幕影像通过二进制流的模式实时传输给录制器,将挪动设施投屏到咱们的录制器上。同时还须要实时获取挪动设施上的 UI Tree,当咱们在录制器上进行鼠标挪动时,利用鼠标在屏幕上的坐标信息从 UI tree 中遍历对应的 UI 元素,并打印该元素的所有 UI 信息。

是不是感觉很简单,不必放心,曾经有成熟的框架 Android Debug Bridge 和 WebDriverAgent 为咱们提供了这些服务,上面👇会重点介绍的。

与挪动设施进行通信的框架

有趣味的同学能够自行 google。

这里咱们间接选用网易的 AirtestProject 作为咱们 UI 自动化的外围框架,起因:

  1. 提供了现成的脚本录制工具 Airtest IDE;
  2. 除了通过 path 定位元素外,还参考 Sikuli 反对图像识别定位 UI 元素;
  3. 相比于 Appium 移除了对 Java,JavaScript、Objective C、Java、Ruby、php、c# 等语言的反对,更加轻量级;
  4. 提供了 Airtest 和 Poco 框架能够在 python 我的项目中间接援用,也反对命令行一键执行;
  5. 提供了更加直观的 report 报告。

Case 治理

解决了 case 的录制问题,上面咱们再来思考 case 的治理问题,在录制 case 的过程中咱们发现很多 case 都存在高度可复用模块,如登录模块,可能咱们 80% 的 case 中都进行了登录操作,若某个版本中登录页面的 UI 产生了改变,导致元素的 path 产生了扭转,这个时候咱们难道要找到所有设计到登录的 case,一一进行批改吗?

其实在编写 UI 自动化 case 时,咱们同样也须要设计模式,参考业界优良模式,再联合我司理论场景,整顿的大体思路入下:

根底层

  • 罕用操作封装:抽离反复代码,进行封装;
  • 工具类封装:数据校验,设施信息获取,安装包数据查问,依照包下载等操作;
  • 埋点遍历封装:以单个页面为单位,获取所有可点击,可滑动,可编辑的 UI 元素,再模仿相应的用户行为;
  • 利用程序安装卸载封装:依据 udid 获取各版本对应的安装包,进行笼罩装置,或卸载装置;
  • 零碎设置封装:切换环境,ab 试验,网络环境;
  • 版本抉择封装:指定 case 运行的版本区间。

业务层

  • 页面封装:依照性能划分,如评论相干操作,登录相干操作等,将这些通用局部抽离并封装,供所有测试 case 调用;
  • 模块封装:进入某个业务模块的前置路基封装等。

用例层

  • 测试用例集:依照业务分子文件夹,蕴含该业务的所有测试用例。

框架层

  • suit:寄存用于组织不同用例集的 Suit 类;
  • report:生成单个 case 的 report 报告,和整个 suit 的聚合报告。

APP 安装包治理

接入公布平台,定时轮训获取提测后的测试包和灰度包信息并落库。表构造如下:

CREATE TABLE `lab_package` (`id` bigint(20) NOT NULL AUTO_INCREMENT,
  `version` varchar(32) CHARACTER SET utf8mb4 DEFAULT ''COMMENT' 版本号 ',
  `buildVersion` varchar(32) CHARACTER SET utf8mb4 DEFAULT ''COMMENT' 构建版本号 ',
  `bundleId` varchar(255) CHARACTER SET utf8mb4 DEFAULT ''COMMENT' 包 ID',
  `pkgPath` varchar(255) CHARACTER SET utf8mb4 DEFAULT ''COMMENT' 包存储门路,能够用来下载包体 ',
  `platform` varchar(255) DEFAULT NULL COMMENT '平台 ios/android',
  `timestamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `branch` varchar(255) DEFAULT NULL COMMENT '所属分支',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=579001 DEFAULT CHARSET=utf8;

在 case 指定版本范畴时,从数据库中查问最新的符合要求的依照包地址(iOS 端存在多个不同 bundleId 的安装包,须要先依据设施的 udid 获取正确的 bundleId),而后下载安装包并装置到运行的设施上。

接入 mock 平台

UI 自动化 case 运行时,最大的困扰是 UI 界面的变动。然而如果咱们接入 mock 平台,保障 case 运行时的界面和 case 编写时的界面以及数据是完全相同的,那么咱们在执行 case 时校验验证点,将会变的轻而易举。

分布式

后面咱们筹备工作做好当前,就要思考 case 运行的问题了。不同于接口自动化,UI 自动化依赖于实在的设施,然而设施资源是无限的,咱们在一台 Mac 上运行时,依据 Mac 的性能,最多能够同时管制几台设施,然而当咱们心愿批量运行 case 时,可能须要在几十台甚至几百台设施上同时运行咱们的 UI 自动化 case。此时咱们就须要分布式了,搭建一个手机 lab 集群,由一台 server 分配任务,多台 worker 执行工作,近程管制连贯在该 worker 上的挪动设施,最初再将所有的 report 报告进行聚合。

lab 框架

语言:python

外围框架:tornado+celery+redis

整体架构:

lab 次要分两个模块,server 调度服务,以及 worker 集群。当 server 服务接管到用户执行指令时,会去 case 仓库遍历合乎用户要求的 case 脚本,由 broker 中间件将工作别离调配给 worker 集群,各 worker 工作执行完结后,会将每个 case 的执行后果存储到 result 后果集之中,待工作全副执行完结 server 会生成总的聚合报告,并将 report 报告通过飞书发送给用户。

其中 worker 的整体架构如下:

当 worker 收到工作后,会开启多过程在连贯的挪动设施上批量执行 UI 自动化 case,

值得一提的是,worker 中本地资源的治理,别离是对安装包的治理和对 case 仓库的治理;

case 仓库其实是 lab 我的项目的子模块,测试人员在日常 case 的编写和保护都是在 case 仓库的我的项目中实现的,齐全不必关怀 lab 我的项目的保护;当有测试同学 push 代码到近程仓库时,Jenkins 就会调用 server 服务的接口,由 server 服务告诉各个 worker 更新 case 仓库的代码即可,保障 worker 在批量运行自动化 case 时,代码是最新的;

安装包的治理:有两种模式,worker 服务除了每天定时获取最新的安装包列表缓存到本地外,当 case 执行时若本地安装包无奈满足版本要求,worker 也会遍历 app 安装包的数据库,将适宜的安装包缓存在本地并装置到挪动设施中;

因为咱们的 app 每天都在进行着很多的版本迭代,相应的咱们的 case 可能只能在局部版本区间中运行,那么咱们此时就须要在 case 中限度版本区间,当 case 运行时,判读设施中已装置的 app 版本是否在该区间内,若不存在则下载安装满足要求的版本到挪动设施中再去执行 case;

更多更细节的设计这里就不再介绍了,有趣味的同学留言探讨哦~

文|crystal

关注得物技术,携手走向技术的云端

退出移动版