得物技术分布式 UI 自动化实践

前言

提起 UI 自动化测试,老是会有人抛出不少疑问:php

  1. UI 自动化能带来什么价值吗?仍是在浪费时间?
  2. UI 自动化测试在整个测试流程中扮演什么样的角色?
  3. 有编写 UI 自动化测试的时间,我早就完成业务测试了,我为何还要编写自动化测试的 case 呢?
  4. 针对于 UI 界面常常变更的业务场景,编写和维护自动化 Case 简直太难了,怎么样才能解决这些问题呢?

......python

今天小编就在这里跟你们分享下,本身对 UI 自动化测试的理解以及我司质量平台正在搭建的分布式平台 DuLab 是怎样实现批量运行 UI 自动化测试 Case 的。android

为何要作 UI 自动化?

随着不停的版本迭代,软件新增功能变的愈来愈多,对测试资源的需求也变得愈来愈大,执行人工测试的时间愈来愈长。对于人工测试的依赖开始变得棘手,所以你们开始寻找解决方案,UI 自动化也应运而生。ios

人工测试的弊端

  • 人工回归测试须要花费很长时间才能完成,很小的延迟就会让发布面临风险。
  • 发布节奏受到人工回归测试的限制。两天以上的人工回归测试意味着最好的状况下可以一个月发布两次。并且,开发者须要一次性发布全部东西。要么所有发布,要么什么都发布不了,由于须要将全部东西一块儿测试。

UI 自动化测试的优势

  • 解放了测试团队针对临时的和探索性案例的测试时间;
  • 能够一边开发一边进行回归测试,减小等待时间;
  • 可重复性使用,快速进行回归测试;
  • 更好的利用资源(周未/晚上的资源空闲时段)。

UI 自动化的特色

UI 即 User Interface(用户界面)的简称,UI 自动化作的事情就是模拟用户行为进行操做,完成对用户界面的测试。这也就从本质上限制了它的使用场景:redis

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

因此在你开始以前,最好认识清楚哪些业务场景是能够自动化的~数据库

预期效果

针对我司的业务现状,肯定好预期效果。c#

  • 兼容性测试:针对市场上经常使用机型与系统版本,进行下载安装使用,以发现兼容性故障,进而修复。
  • 埋点测试:校验埋点数据是否正常上报,有无漏报,错报,多报。
  • 回归测试:版本迭代中,进行回归测试保障代码改动不会致使其余场景产生故障。
  • 测试阶段性能收集:在测试阶段为自动化 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

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

相关文章
相关标签/搜索