综述
本文主要介绍了多端自动化的实践经历而非作为airtest的科普文章(因为airtest的官方文档真的是已经特别全了,非常建议实践之前先看一遍文档,大部分问题都能达到答案),主要叙述了在面对多端大规模场景时,自动化的技术选型、方案设计、实践难点等等。
项目背景介绍
所在项目是一个多端互动的场景,是一对多的业务实现,具体是由一台winpad的教师端,对多台安卓的学生端,在同一局域网内,进行指令的发送和接收,从而产生互动,指令的中转由台服务(服务器 AP)实现。
需求产生的背景介绍
原始的客户诉求,是因为业务测试在执行这样一对多的测试(以下简称为大规模互动)中,因为需要真实模拟场景,所以往往需要在一台教师端和60台学生端之间来回操作,极为消耗人力资源(平均一次大约需要2人1天的工时),因此希望得到一种技术手段,节约在大规模互动测试中的开销。
技术选型
基于原始的客户诉求,我们将具体实现定义为了ui自动化类型,以下是技术选型的分析过程。
技术要求
- 统一性
大规模互动产生在不同的系统间,教师端的系统是win10,而学生端的系统是android,因此,我们希望最好可以由同一套框架实现对两端的驱动,这样整体便于设计和驱动。
- 高兼容性
由于教师端的实现并不是标准的windows应用实现方法,而是通过c nodejs再由electron做封装,因此,很多元素用传统的windows的查找框架uiautomation不易找到,而由于客户端对webview的实现写死了启动参数,因此也无法通过传统的cdp进行定位,因此,我们希望可以有一个相对兼容的解决办法去定位元素。
- 低侵入性
在学生端,有着rom级的mdm安全管控,对安装应用、网络进出、adb连接等待都有着严格的规则,且mdm是和供应商联合制定的,如果要对某些地方放行,会面临较大的实现成本问题,因此,我们希望整体的实现方案具有较低的侵入性。
方案对比
经过调研,具备以上要求的方案大概有以下:
- airtest
网易出品的主打图像识别的开源自动化测试框架,具备三端(web、移动、win)驱动能力;且相关ide、文档、使用经历较为齐全。
- 腾讯QTA
腾讯出品的开源自动化测试框架,具备三端驱动能力,但截至调研期间,其win端的驱动包还未放出。
- 学生端appium 教师端pywinauto
appium是老牌的移动端测试框架,pywinauto是win端的gui测试框架,他们皆可由py进行封装驱动。 但appium存在需要在移动端安装其服务apk以及通信的需求,会受到mdm管控。
- 学生端AccessibilityService 以上教师端方案
通过AccessibilityService可以实现学生端的元素控制,使得学生端可以无需连接控制设备,直接在本机即可运行,但后续扩展能力较低,且难以与教师端实现相互通信。
综合以上选择,认为 airtest
现阶段较为合适,并且由于是局域网内的大规模通信场景,对无线带宽本身就有压力,因此,对学生端的驱动方式采用有线adb而非无线的方式。
方案设计
整体架构
原本更为合适的架构形态可能是通过rpc的方式完成端对端通信(具体参见文档: 基于rpc的多端互动自动化方案 ),由于时间和人力所限,最后简化为端对端之间互不通信,学生端通过元素轮询完成教师端行为的响应,具体架构如下:
1.环境需求 :
硬件
- 学生端执行服务器 *2台;
- 教师端执行服务器 *1台(如果也在学生端执行服务器上那么可以没有);
- UsbHub *2台;
- 学生pad *60台;
软件
- 学生端脚本;
- 教师端脚本
网络
- 局域网环境(超脑环境)
2.执行过程:
usbhub分别连接上各30台学生端机器以及执行学生端脚本的服务器; --> 在学生端执行服务器上启动学生端脚本,此时学生端进入元素轮询状态; --> 在教师端执行服务器上启动教师端脚本,通过教师端本身的反馈判断学生端是否做完对应动作 --> 收集测试结果
脚本设计
脚本架构
脚本的基本设计采用元素映射关系、配置文件、执行步骤互相分离的方式,各端的脚本放置在xxx.air的文件夹里,通过airtest本身的启动cli执行。 脚本的目录结构 大致如下:
代码语言:javascript复制|-- configs(存放项目运行设置的配置文件目录)
|'-- run.config
|-- logs(记录运行时log文件的目录)
|-- templates(存放报告模板目录)
|'-- report_tpl.html
|-- test_XXX.air(某个端的执行脚本)
|'-- action.config(某个端的运行配置)
|'-- element.config(某个端的元素映射文件)
|'-- test_xxx.py(某个端的执行动作脚本库)
|'-- utils.py(工具集方法)
|-- valid_pic(存放断言用图片的目录)
|-- run.py(总运行入口)
脚本实现能力
脚本主要实现了以下能力:
- 覆盖了学生端、教师端的互动主要场景的动作执行;
- 覆盖了互动主要场景的耗时统计;
- 教师端、学生端分别由配置文件定制主要场景的执行细节(例如执行次数,动作参数等等)
- 集成了非主要场景但是常用的工具集(例如adb连接检测,自动安装卸载apk等等)
- 。。。
关键技术点实现
- 多进程驱动学生端执行用例
由于互动场景基于1对多,在学生端这边需要多台设备进行场景互动,因此,需要同时驱动多台设备,在实现上,我们查阅了官方资料,采用了其建议的方式,通过起多个进程,每个进程分别带参执行airtest的cli命令,从而达到多设备驱动的目的。
- 图像识别下的断言
如前文,在精简的框架设计下,多端互动是通过学生端轮询元素来执行互动流程的,但是仍然需要对互动结果的正确性进行校验。这里由于框架的限制,我们只采取了单端校验,即只对教师端的互动数据进行校验,比如如果有30个学生作答成功,那么我们就对教师端的结果页面进行校验,看答题人数是否是30。
具体到校验手段,由于windows端较难获取元素属性,所以我们采用了对关键点进行ocr识别的方式,具体请见文档 在airtest中使用ocr反向识别进行断言 。
- 执行过程内性能数据的收集
数据收集是指在执行过后,需要给出场景的耗时,例如指令的接受耗时、页面的加载耗时等等,这块主要是通过在学生端设备上记录一个时间,作为开始时间,然后测试结束后,提取该设备上的日志分析,最后得出耗时数据。
- 易混淆元素的记录
由于采用的是图像识别的模式,难免遇到元素图像相似的情况,针对这种情况,采用的方法是扩大可识别范围截取元素,并使用target_pos参数更改选取区域。
应用过程问题与解决
本部分以问答的形式展现在airtest应用过程里存在的一些问题和解决办法。
- 为什么执行windows端脚本的时候,鼠标可以移动到元素上但是执行动作失败?
在win端,airtest的底层是pywinauto,并且基本没有任何二次开发;遇到这个问题,如果排除掉本身脚本的逻辑、语法问题,那么可以试试以管理员身份运行脚本。
- 我必须要用官方的ide嘛?
airtest虽然附带了一个官方的ide,但是非常不建议把它用作项目的ide,作为项目级的ide还是比较欠缺工程目录管理能力和基本的代码检查能力等; 建议的方法是,ide仅用作抓取元素时的录制工具,但是项目级别的管理最好还是使用知名的ide。
- 为什么有些windows的窗口用title连接不上?
如果不是你的语法有问题,并且你“看起来”title写的也对,那么可以在识别的时候在pywinauto的底层代码里,打个断点,把所有窗口名称用bytes类型打印出来看一下; pywinauto的连接过程里,是先遍历所有窗口,然后按你的连接类型做匹配,这里打个断点,可以看一下你写的title是不是真的对,因为在实际的项目里,我们遇到了看起来是对的title名称,但是无论如何匹配不上,导致无法连接,最后用bytes模式打印出来看,发现是因为这个窗口的title前面有三个不可见字符(直接print你是看不见的)。
- 如何提高元素的查找速度?
和传统的通过元素属性查找的方式不同,airtest是基于图像识别的,因此,在提高元素查找效率方面,方法也和传统的有些不同;一个基本的原则是,被查找的元素的截图,在整个画面里越独一无二,越具备特征性(图形的特征性而不是颜色),那么就越容易被找到;此外,在对元素的映射关系记录里,增加record_pos和resolution的值,会极大的增加查找速度和效率。
- 怎么对没找到元素的情况进行调试?
和传统的通过元素属性的查找方式不同,基于图像识别的查找方式不存在找不到元素,对图像识别而言,它总是能找到元素的,区别只是查找到元素的匹配度(threshold)而已,airtest默认的threshold是0.7,也就是说,在他认为元素的匹配度为70%以上时,就认为找到了这个元素,才会对这个元素进行操作。 不幸的是,往往达到0.7,也不一定就是真的找到了(但达不到一般是真没找到),如果达不到匹配度,或者达到了但也不对,可以在airtest的框架里打断点。 airrtest的查找机制是先把当前待查找的界面进行截图,我们称为图1;然后再根据你的record_pos,在图1里算出待识别区域,然后把这个区域抠出来保存,我们称为图2;最后,再把你的预先截图的元素,在图2里进行查找,算出匹配度,如果匹配度在要求之上,那么就记录这个位置的坐标用于操作。 因此,我们可以分别对图1,图2设定指定的保存目录,执行一遍后看一下,到底是对比对象出了问题,还是真的我们元素截图特征还不够。