提起 UI 自动化测试,老是会有人抛出不少疑问:php
......python
今天小编就在这里跟你们分享下,本身对 UI 自动化测试的理解以及我司质量平台正在搭建的分布式平台 DuLab 是怎样实现批量运行 UI 自动化测试 Case 的。android
随着不停的版本迭代,软件新增功能变的愈来愈多,对测试资源的需求也变得愈来愈大,执行人工测试的时间愈来愈长。对于人工测试的依赖开始变得棘手,所以你们开始寻找解决方案,UI 自动化也应运而生。ios
UI 即 User Interface(用户界面)的简称,UI 自动化作的事情就是模拟用户行为进行操做,完成对用户界面的测试。这也就从本质上限制了它的使用场景:redis
因此在你开始以前,最好认识清楚哪些业务场景是能够自动化的~数据库
针对我司的业务现状,肯定好预期效果。c#
与接口自动化测试思路相同,咱们在进行 UI 自动化测试时,每一个 Case 都是一个单独的 TestCase,咱们将全部须要执行的 case 放在同一个 TestSuit 中,批量执行并生成聚合报告。设计模式
下面是小编本身从点到面一步步的思考历程,从基本的移动设备远程管理,case 编写到 case 的维护,再到 lab 平台的搭建:缓存
目前市面上有不少成熟的 UI 自动化工具,如appium,airtest,Sikuli等等,它们提供了很是便捷的录制服务,咱们只须要在 idea 上拖拖拽拽,立刻就能够生成一个简单的 UI 自动化脚本,且咱们只须要将这些工具封装的工具库部署在咱们的电脑上就能够屡次运行咱们编写的 case 了。网络
这里咱们将分开剖析进行 UI 自动化用到的录制器和执行器的原理:
解读其源码咱们发现这些工具其实底层的实现原理都基本相同,核心即为:对移动设备的远程控制,并将控制指令封装为可读通用的语法。
其实咱们平常使用手机时,手机系统就是经过咱们点击的屏幕坐标,从最上层的 view 依次向下遍历,直到找到该坐标位置下能够响应用户行为的 UI 控件,执行对应的响应代码。
可是咱们在编写 case 时,若是 case 中记录的全是在某个坐标下对应的操做行为的话,就会特别的晦涩难懂,且针对不一样屏幕尺寸的设备也彻底不通用,这显然是行不通的。
真实的用户行为其实无非就是,点击了某个按钮,滑动了某个页面等等,主体其实就是 UI 控件,咱们在编写 case 时也是同样的,我但愿的是对某个 UI 控件进行操做,那么其实在执行 case 时,咱们彻底能够获取该 UI 控件在当前屏幕中的位置,再去调用底层的控制指令进行操做。
其实 case 录制的原理就是上述执行原理的逆向思惟,咱们能够在移动设备上开启 server 服务,将移动设备的屏幕影像经过二进制流的形式实时传输给录制器,将移动设备投屏到咱们的录制器上。同时还须要实时获取移动设备上的 UI Tree ,当咱们在录制器上进行鼠标移动时,利用鼠标在屏幕上的坐标信息从 UI tree 中遍历对应的 UI 元素,并打印该元素的全部 UI 信息。
是否是感受很复杂,不用担忧,已经有成熟的框架 Android Debug Bridge 和 WebDriverAgent 为咱们提供了这些服务,下面👇会重点介绍的。
有兴趣的同窗能够自行 google。
这里咱们直接选用网易的AirtestProject做为咱们 UI 自动化的核心框架,缘由:
解决了 case 的录制问题,下面咱们再来思考 case 的管理问题,在录制 case 的过程当中咱们发现不少 case 都存在高度可复用模块,如登陆模块,可能咱们 80%的 case 中都进行了登陆操做,若某个版本中登陆页面的 UI 发生了改动,致使元素的 path 发生了改变,这个时候咱们难道要找到全部设计到登陆的 case,逐个进行修改吗?
其实在编写 UI 自动化 case 时,咱们一样也须要设计模式,参考业界优秀模式,再结合我司实际场景,整理的大致思路入下:
接入发布平台,定时轮训获取提测后的测试包和灰度包信息并落库。 表结构以下:
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),而后下载安装包并安装到运行的设备上。
UI 自动化 case 运行时,最大的困扰是 UI 界面的变更。可是若是咱们接入 mock 平台,保障 case 运行时的界面和 case 编写时的界面以及数据是彻底相同的,那么咱们在执行 case 时校验验证点,将会变的垂手可得。
前面咱们准备工做作好之后,就要考虑 case 运行的问题了。不一样于接口自动化,UI 自动化依赖于真实的设备,可是设备资源是有限的,咱们在一台 Mac 上运行时,根据 Mac 的性能,最多能够同时控制几台设备,可是当咱们但愿批量运行 case 时,可能须要在几十台甚至几百台设备上同时运行咱们的 UI 自动化 case。此时咱们就须要分布式了,搭建一个手机 lab 集群,由一台 server 分配任务,多台 worker 执行任务,远程控制链接在该 worker 上的移动设备,最后再将全部的 report 报告进行聚合。
语言: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
关注得物技术,携手走向技术的云端