
质量架构 - UI自动化平台
UI 自动化测试平台 整体建设实践已在 QECON 大会以及期刊中做了分享。
本文主要梳理部分技术实现细节和思路,由于使用的都是开源技术且很多也是受别人分享的启发,应该会具有通用性
UI 自动化业界调研
现有平台/产品
1. 云测 testin
支持端类型:web/windows
平台特色:
NLP 识别指令
支持远程传输与控制
控件识别
2. MeterSphere 飞致云
- 支持端类型:web
- 平台特色:
- 测试报告完善
3. 影刀 RPA
- 支持端类型:web/windows
- 平台特色:
- 指令集完善
- 交互简单易用
- 控件定位多种方式检索
4. 网易 Airtest
- 自持端类型:web/windows
- 平台特色:
- 自研 IDE 客户端
- 支持图像识别/OCR/Poco
现有的商业化产品基本可以满足我们的需求,但是主要有如下缺点:
收费,部署成本高(1 2)
测试报告不够完善(3 4)
缺少定制化能力,比如无法对接公司 CICD 、数据度量管理 (1 2 3 4)
技术选型
web UI 测试框架

Windows UI 测试
- 微软 UI automation:支持微软提供的各种开发框架,兼容性更好
- Java 封装 ms ui-automation:https://github.com/mmarquee/ui-automation
- pywinauto
- Windows API : 基于窗口句柄查找
- pywinauto
- MSAA - Accessibility
核心执行流程
数据结构
平台将一个用例的连续执行过程,拆分为一系列具有相同数据结构的"步骤"。每个步骤由【指令】+【数据】信息组成。
【指令】集合包含基础能力、循环、条件判断等大类:
- 基础指令集覆盖自动化测试常用操作(鼠标/键盘/SQL/客户端/文字识别等等),他的特点为单一指令 无子步骤,基础指令的步骤是最细粒度的步骤。
- 循环/条件判断:循环指令可以使得包含重复性步骤的用例更加简洁,条件判断增强了用例的兼容性和扩展性。这两个指令特点是他们通常会包含众多基础指令,也有可能继续嵌套循环/条件判断指令。
另外,平台还建立了【元件】的概念:它的主要功能是能让不同用例复用同样一系列步骤(比如用户登录),使得用例更加简洁 增强可读性。用例可以引用元件(但是元件不能再引用元件),用例也可以使用元件中的变量。
不难想到,在执行上述结构的用例/计划与树的遍历过程十分相似,即:
递归遍历设计
当然,"遍历"操作会更加复杂,包括不限于:
异常捕获 ⭐️:这里十分重要,一个 1000+步骤的用例如果因为一个未捕获异常而执行失败,用户会崩溃的!
- GlobalExceptionHandler:全局异常捕获
- xxxExceptionHandler
- try... catch ... finally : catch 尽量避免 Exception
报告数据生成 ⭐️:提供一份数据准确、执行过程信息清晰的报告十分重要(尤其是接入 devops 准出门禁后)
- 数据对账
- 统一处理
- 事务
步骤中变量替换
- 静态变量:前置统一替换
- 动态变量:
机器/报告的状态跟踪
循环/元件等包含子步骤的处理:
动作指令执行(鼠标/键盘/SQL 查询/OCR/表格解析/客户端/智能等待...)
//伪代码
//执行当前节点下的所有一级步骤(当前节点有可能是元件、循环)
public HashMap runSteps(){
//依次执行当前节点的子步骤
for (int i=0;i<steps.size();i++){
//判断是否需要终止(取消执行操作)
if (shouldStop()){
break;
}
//判断是否需要跳过(禁用)
if (shouldSkip()){
continue;
}
if (steps.get(i).getType == "Loop"){
//preHandler:数据集数据处理
preHandler();
for (int startIndex = start; endIndex< end; startIndex+=inc){
//数据驱动,替换变量
}
Result = runSteps(steps.get(i));
//处理本次的结果
postHandler();
}else if ("元件"){
JSONArray modsChildrenSteps = steps.getJSONObject(i).getJSONArray("children");
HashMap<String, Object> childrenResultMap = runSteps(map, obj, modsChildrenSteps, steps, contextVarMap);
//步骤计数器(成功、失败)
countSteps();
//handleResult:如果成功,那么插入一条记录继续执行,如果失败那么生成后续步骤为跳过并插入
}else if ("SQL"){
SqlOperation.excute();
}else{
instance.runInstanceFunction();
}
}
IO 模型优化
这里的优化思路主要参考了 Quake:
https://www.51cto.com/article/720420.html > https://tech.meituan.com/2016/12/02/performance-tunning.html
在最初的用例执行设计中,步骤中的上传截图/数据读写等 IO 操作简单粗暴地采用 BIO 方式,但上线后立马接到了性能方面的反馈。
经排查,【上传截图】操作的额外耗时最严重(每个步骤通常会包含 19201080 地全屏截图1、小尺寸图像识别模板图1 以及 19201080 识别结果图*1),此外每个用例还会上传一份录制视频和一些调试图片,平均会增加 500-800ms/步骤,1000 个步骤的用例会因此多执行将近 13 分钟!
- 优化方案 1 改为@Async,这样实现改动很简单,也实现了同步改异步的优化。但是仍然是阻塞 I/O,在较高并发度的场景下性能还有改进空间
- 优化方案 2 改为 Reactor 异步非阻塞 I/O,业务逻辑与读写分别在不同的 worker 完成
反射调用指令集
UI 自动化指令集超过 30 种,需要实现统一配置、调用、异常捕获的逻辑
解决方案:Operation 表 + 反射调用
慢查询
- 发现:SpringBoot-Acuator
- 比较有效的解决方案:
- 增加索引,或者修复索引失效的 SQL
- select 避免冗余字段,尤其是 context blob 等大字段(SELECT 避免用*)
- 尽量规避子查询
- 尽量单表查询,最多两张
远程传输&控制
为了方便用户在更直观的调试用例,平台支持远程传输和控制能力,即用户可以在平台实时看到执行机画面并可以控制执行机。
实现原理大致如上图,1-3 实现了远程控制;4-6 实现了执行机画面的实时传输。
- novnc 通过 websocket 建立连接,但是 vncserver 仅支持 tcp socket,所以需要实现 websocket 与 tcp socket 的转化功能,主流工具有 Websockify,也可以使用 nginx + node。
定位能力
- xpath
- windows 控件
- 图像识别
- som + GPT4V:这个是逛 github 发现的,京东也有类似的实现思路,和前端一起做了二次改造,可用于定位的兜底(上线需要换成本地大模型,效果稍微差些)