首页 / 资讯中心 / 文章详情

移动端自动化测试双模式架构:控件树与视觉感知的协同实践

移动端自动化测试双模式架构:控件树与视觉感知的协同实践 ★ FEATURED ARTICLE
1. 移动端自动化测试的现状与ARTEMIS的切入点移动端自动化测试这件事做过的人都懂它跟Web端完全不是一个难度量级。Web端你至少有一套相对统一的DOM结构可以抓有成熟的浏览器驱动协议可以调元素定位失败了大不了刷新一下重来。但移动端呢Android碎片化、iOS封闭性、原生控件与混合页面的边界模糊、不同厂商ROM对无障碍服务的魔改再加上真机与模拟器的行为差异每一个都是能把测试工程师逼疯的坑。我最早接触移动端自动化是在一个跨平台应用的项目里当时团队用了一套基于图像识别的方案跑一轮回归测试要四十多分钟而且稍微换个分辨率就大面积失败。后来陆续试过几套主流框架各有各的痛点有的对混合应用支持不好有的在真机集群上稳定性堪忧有的写起用例来比写业务代码还累。所以当看到ARTEMIS这个项目提出“双模式架构”的时候我的第一反应是——终于有人认真在解决移动端自动化的架构层面问题了而不是又在做一个“换个壳的录制回放工具”。ARTEMIS的核心思路其实不复杂但很聪明它把移动端自动化测试拆成了两条腿走路。一条腿是基于UI控件树的精确控制模式适合那些控件层级清晰、ID可用的原生页面另一条腿是基于视觉感知的智能交互模式专门对付那些控件树混乱、动态渲染、甚至游戏引擎绘制的界面。这两种模式不是互斥的而是可以在同一个测试用例里根据页面类型动态切换。这个设计思路直接解决了我之前项目里最头疼的问题——一个App里既有原生页面又有H5混合页还有用Flutter或Unity渲染的部分单一模式根本覆盖不了。这篇文章我会从架构设计的角度把ARTEMIS的双模式拆开来讲清楚。包括它为什么这么设计、两种模式各自的实现原理、在实际项目中怎么配置和切换、以及我在试用过程中踩过的那些坑。如果你正在做移动端自动化测试的选型或者已经被现有方案的稳定性折磨得不行这篇内容应该能给你一些直接的参考。2. 双模式架构的设计逻辑与核心取舍2.1 为什么单一模式在移动端走不通在深入ARTEMIS的架构之前有必要先搞清楚一个问题为什么移动端自动化测试不能像Web端那样用一套统一的方案搞定所有场景答案藏在移动端的技术栈碎片化里。一个典型的移动应用它的界面可能由以下几种技术渲染而成原生控件Android的View体系、iOS的UIKit、WebView里的H5页面、跨平台框架的自绘引擎Flutter、React Native的部分组件、甚至游戏引擎的直接GPU绘制。这四种渲染方式对于自动化测试工具来说可访问性是完全不同的。原生控件有完整的无障碍树你可以通过ID、类名、文本内容精确定位。H5页面在WebView内部理论上可以通过注入JavaScript来操作DOM但前提是WebView开启了调试开关而且跨域限制、异步加载这些问题都会影响稳定性。Flutter这类自绘引擎最麻烦它把所有控件画在一张画布上无障碍树里可能只有寥寥几个节点传统的控件定位方式基本失效。游戏引擎就更不用说了整个界面就是一张不断变化的位图。我见过太多团队试图用一套方案打天下结果就是在原生页面上跑得好好的用例一到Flutter页面就全军覆没。然后开始打补丁加图像识别、加坐标点击最后维护成本高到没人愿意碰。ARTEMIS的双模式架构本质上是对这个现实的妥协但妥协得很聪明——它不是在一个模式里堆砌各种补丁而是从架构层面把两种根本不同的交互方式分开设计让它们各自发挥优势。2.2 精确控制模式与视觉感知模式的边界划分ARTEMIS把两种模式分别叫做Precision Mode和Vision Mode我更喜欢用“控件树模式”和“视觉模式”来理解它们。控件树模式的工作方式跟Appium、Espresso这些传统框架类似它通过平台提供的无障碍服务或测试框架API获取当前界面的控件树结构然后基于控件的属性ID、文本、类名、层级关系来定位和操作元素。这种模式的优点是精确、快速、对界面外观变化不敏感。只要控件的ID不变你把按钮从左边移到右边、从红色改成蓝色用例都不会失败。缺点是依赖控件树的质量遇到自绘引擎或动态生成的界面就抓瞎。视觉模式则完全绕开控件树它通过截屏获取当前界面图像然后用计算机视觉技术来识别界面上的元素。ARTEMIS在这部分用了一套轻量级的视觉模型能够识别常见的UI组件按钮、输入框、列表项、图标等并返回它们的坐标和置信度。这种模式的优点是对界面实现方式不敏感管你是原生还是Flutter还是游戏引擎只要人眼能看到的它就能识别。缺点是受分辨率、主题、动效、遮挡等因素影响较大而且识别速度比控件树模式慢一个数量级。ARTEMIS的聪明之处在于它没有试图让一种模式去覆盖另一种模式的场景而是定义了一套模式切换协议。在测试脚本里你可以显式地指定某个步骤使用哪种模式也可以设置自动切换规则——比如当控件树模式连续多次定位失败时自动降级到视觉模式重试。这个设计让测试用例的编写者可以根据页面类型灵活选择而不是被框架的限制绑架。2.3 双模式架构带来的核心优势与代价从实际使用的角度来看双模式架构带来的最大好处是覆盖率和稳定性的提升。覆盖率方面以前需要写两套用例一套给原生页面一套给特殊渲染页面的场景现在可以在一个用例里完成。稳定性方面当某个页面因为开发改了实现方式导致控件树变化时视觉模式可以作为兜底方案避免用例直接失败。但代价也是实实在在的。首先是复杂度的增加测试工程师需要理解两种模式的工作原理和适用场景才能写出高效的用例。其次是执行速度的波动视觉模式的引入会让整体测试时间变长特别是在需要频繁截屏和识别的场景下。最后是调试难度的上升当一个用例失败时你需要判断是控件树模式的问题还是视觉模式的问题排查路径比单一模式要长。ARTEMIS对这些代价的处理方式是提供详细的执行日志和截图记录每一步操作都会标注使用的模式、定位到的元素、置信度等信息。这个设计在实际调试时非常有用我后面会专门讲怎么利用这些日志来快速定位问题。3. 控件树模式的实现细节与实操要点3.1 控件树获取的底层机制ARTEMIS在Android端获取控件树的方式主要是通过无障碍服务AccessibilityService来实现的。这个选择其实有讲究。Android平台提供了多种获取界面信息的途径比如UiAutomator的API、Instrumentation框架、以及无障碍服务。UiAutomator适合跨应用操作但需要adb连接且速度较慢Instrumentation只能操作被测应用自身无法处理系统弹窗无障碍服务的优势在于它是系统级服务可以获取任意应用的界面信息而且不需要root权限。具体来说ARTEMIS会在设备上安装一个轻量级的辅助应用这个应用声明了无障碍服务权限。当测试开始时辅助应用通过无障碍服务监听当前活动窗口的变化并在需要时调用getRootInActiveWindow()获取控件树的根节点。然后通过递归遍历把整个控件树序列化成JSON格式传回测试执行端。这个过程听起来简单但实际实现时有几个关键细节。第一是刷新时机的控制无障碍服务的事件回调是异步的如果界面还在渲染中就获取控件树很可能拿到不完整的结构。ARTEMIS的做法是在获取控件树之前先等待界面稳定——具体来说它会监听TYPE_WINDOW_CONTENT_CHANGED事件在最后一次内容变化后等待一个可配置的静默期默认500毫秒然后再抓取。这个静默期的设置很关键太短了容易抓到中间状态太长了会拖慢测试速度。第二是控件树裁剪。一个复杂页面的控件树可能有上千个节点全部传回执行端会消耗大量网络带宽和序列化时间。ARTEMIS会根据当前操作的目标只保留与定位相关的属性ID、文本、类名、bounds、可见性等并且会剪掉不可见或不可交互的子树。这个优化在实际使用中效果很明显我实测过一个包含长列表的页面裁剪后的控件树大小只有完整树的十分之一左右。3.2 元素定位策略与优先级在控件树模式下元素定位的准确性直接决定了用例的稳定性。ARTEMIS提供了一套多级定位策略按照优先级从高到低依次尝试优先级定位方式适用场景稳定性1资源ID原生控件且有明确ID最高2无障碍标签有contentDescription的控件高3文本内容按钮、标签等文本控件中4类名索引同类控件中的第N个低5相对位置基于其他已定位元素的方位关系中这个优先级的设计逻辑是越靠上的定位方式对界面变化的抵抗力越强。资源ID通常是开发在布局文件里写死的不会因为界面调整而改变无障碍标签虽然也可能变但它的语义性更强变化频率较低文本内容容易受多语言和文案调整影响类名索引最脆弱列表顺序一变就失效。我在实际使用中的经验是尽量把定位方式控制在优先级1和2。如果开发没有给某个关键控件加ID宁可去提一个需求让他们加上也不要图省事用文本或索引定位。这个前期投入在后期回归测试时会成倍地回报回来。ARTEMIS支持在定位失败时自动降级尝试下一优先级但这个功能我建议只在调试阶段开启正式用例里还是显式指定定位方式更可控。3.3 控件树模式的实操配置与注意事项配置ARTEMIS的控件树模式主要涉及以下几个参数precision_mode: tree_fetch_timeout: 5000 # 控件树获取超时毫秒 stability_quiet_period: 500 # 界面稳定静默期毫秒 max_tree_depth: 20 # 最大遍历深度 include_invisible: false # 是否包含不可见控件 attribute_filter: # 需要保留的属性 - resource_id - text - content_desc - class_name - bounds - clickable - enabled这里有几个参数值得展开说。stability_quiet_period我一般会设到800毫秒左右特别是在低端设备上500毫秒有时候还是会抓到渲染中的界面。max_tree_depth默认20层对大多数应用够用但如果你的应用有特别深的嵌套布局可能需要调大不过要注意性能开销。include_invisible建议保持false除非你需要操作那些透明度为0但实际可点击的“幽灵按钮”——这种情况在某些广告SDK里确实存在。注意无障碍服务在部分定制ROM上会被系统杀后台导致测试中途失联。ARTEMIS提供了心跳检测和自动重连机制但在真机集群上跑长时间测试时还是建议把辅助应用加入电池优化白名单。还有一个坑我踩过某些应用会检测无障碍服务是否开启如果检测到就改变界面行为比如隐藏某些控件。这种情况下控件树模式会拿到一个“阉割版”的界面定位自然失败。应对方式是在测试配置里开启ARTEMIS的隐身模式它会尽量模拟普通用户的无障碍使用特征降低被检测的概率。但这个模式不是万能的遇到特别激进的反无障碍检测还是得回到视觉模式。4. 视觉感知模式的原理与落地实践4.1 视觉识别模型的技术选型ARTEMIS的视觉模式在技术选型上做了一个很有意思的平衡。它没有直接用那些重量级的通用目标检测模型比如YOLO系列而是训练了一个轻量级的UI组件识别模型专门针对移动端界面上的常见元素。这个决策背后的逻辑是通用目标检测模型虽然泛化能力强但参数量大、推理速度慢在移动端设备上跑一轮识别可能要几百毫秒甚至上秒对于需要频繁交互的测试场景来说太慢了。而UI组件识别这个任务其实相对封闭——界面上的元素类型就那么几种按钮、输入框、文本、图标、列表项、开关等而且它们的视觉特征比较固定不需要模型有太强的泛化能力。ARTEMIS的视觉模型基于一个精简的主干网络参数量控制在几MB级别在主流移动设备上单帧推理时间可以做到50毫秒以内。识别输出包括每个元素的边界框、类别标签和置信度。对于文本内容它还会调用系统的OCR能力Android用ML KitiOS用Vision框架来提取文字这样就能支持“点击文本为‘登录’的按钮”这类语义化操作。我在实测中对比过ARTEMIS的视觉模式和几个开源的UI识别方案在标准分辨率的截图上ARTEMIS的识别准确率能到95%以上速度也明显快一截。但在低分辨率或高DPI缩放的设备上准确率会下降到85%左右这时候就需要调整截图的缩放策略。4.2 视觉模式的操作映射与坐标计算识别出元素之后下一步是把识别结果映射成可执行的操作。这里涉及一个容易被忽略但很关键的问题坐标系转换。ARTEMIS获取的截图是设备屏幕的像素图像而执行点击操作时需要的是设备坐标系下的坐标。这两个坐标系在大多数情况下是一致的但在以下几种场景会出现偏差设备开启了显示缩放、应用处于分屏或画中画模式、截图经过了压缩或裁剪。ARTEMIS的处理方式是在截图时记录当前的显示参数分辨率、密度、缩放比例然后在计算点击坐标时做反向变换。具体来说如果识别到的元素边界框在截图上是(x1, y1, x2, y2)那么实际点击坐标的计算方式是click_x (x1 x2) / 2 / scale_factor click_y (y1 y2) / 2 / scale_factor其中scale_factor是截图分辨率与设备实际分辨率的比值。这个计算看起来简单但如果忘了做这一步点击就会偏到姥姥家去。我在第一次用视觉模式时就犯过这个错误明明识别到了按钮点击却总是落在旁边排查了半天才发现是截图被压缩了。除了坐标转换视觉模式还需要处理元素遮挡和动效干扰。比如一个按钮正在做淡入动画截图时可能只显示了一半识别出来的边界框就不准确。ARTEMIS的策略是在执行视觉操作前先检测界面是否有持续变化的区域如果有就等待动效结束再截图。这个检测是通过比较连续两帧截图的差异来实现的差异小于阈值就认为界面稳定了。4.3 视觉模式的性能优化与缓存策略视觉模式最大的短板是速度。每次操作都要截屏、推理、计算坐标一套流程下来少则几十毫秒多则几百毫秒。如果一个测试用例有上百步操作累积起来的时间就很可观了。ARTEMIS在这方面做了几层优化我实测下来效果比较明显。第一层是截图复用。如果连续多个操作都在同一个界面上ARTEMIS会复用第一次的截图和识别结果而不是每次都重新截屏。这个优化的前提是界面没有发生变化ARTEMIS通过比较当前界面的哈希值与缓存中的哈希值来判断是否需要重新识别。第二层是区域识别。如果操作目标在界面的某个已知区域比如底部导航栏、顶部标题栏ARTEMIS可以只截取该区域进行识别而不是全屏识别。这个优化能把推理时间降低60%以上。配置方式是在用例里指定region参数- action: vision_click target: 设置按钮 region: [0, 0, 1080, 200] # 只在这个区域内查找第三层是识别结果缓存。对于在多个用例中反复出现的界面比如登录页、首页ARTEMIS会把识别结果缓存到本地下次遇到相同界面时直接读取缓存跳过推理步骤。缓存的失效策略是基于界面哈希值的界面一变缓存就失效不会出现用旧结果操作新界面的问题。实操心得视觉模式的缓存虽然好用但在调试阶段建议关掉。因为缓存会让你误以为识别很准实际上可能是用了旧结果。等用例稳定了再开启缓存来加速回归测试。5. 双模式协同工作的配置与切换策略5.1 显式模式指定与自动降级机制ARTEMIS在用例层面提供了灵活的模式指定方式。最简单的是在每一步操作上显式标注使用哪种模式steps: - action: precision_click target: { resource_id: com.example.app:id/login_btn } - action: vision_click target: 同意协议 - action: precision_input target: { resource_id: com.example.app:id/username } text: testuser这种写法最直接适合对页面结构非常了解的情况。但实际项目中页面结构可能会变写死的模式指定在页面改版后就需要调整。所以ARTEMIS还提供了自动降级机制你可以指定一个操作优先使用某种模式如果失败则自动尝试另一种模式。- action: click target: 提交订单 mode: precision_first # 先试控件树失败后转视觉 fallback: vision retry: 2 # 降级后重试次数这个机制在混合页面的场景下特别有用。比如一个页面大部分是原生控件但某个关键按钮是Flutter渲染的你可以统一用precision_first策略原生部分走控件树Flutter部分自动降级到视觉模式用例编写者不需要关心每个元素的具体实现方式。5.2 基于页面特征的动态模式选择除了手动指定和自动降级ARTEMIS还支持基于页面特征的动态模式选择。它的实现方式是维护一个页面特征库记录每个页面的“模式亲和度”——也就是在这个页面上哪种模式的成功率更高、速度更快。这个特征库是自动学习的。每次测试执行后ARTEMIS会统计每个页面上两种模式的成功率和平均耗时然后更新特征库。下次遇到同一个页面时就优先使用成功率高的模式。这个机制在长期运行的测试项目中效果很好相当于让框架自己积累经验。我实测过一个包含二十多个页面的应用跑了一周之后特征库基本能准确判断每个页面该用哪种模式整体测试时间比固定模式策略缩短了约30%。不过这个机制有个前提页面要有稳定的标识比如Activity名或URL否则特征库无法正确匹配。5.3 模式切换的性能开销与优化建议双模式切换不是没有代价的。每次从控件树模式切到视觉模式都需要重新截屏和识别从视觉模式切回控件树模式需要重新获取控件树。这些操作都有时间开销频繁切换会显著拖慢测试速度。我的优化建议是尽量把同一模式的操作集中在一起。比如一个页面先用控件树模式完成所有原生控件的操作然后一次性切换到视觉模式处理特殊元素处理完再切回来。ARTEMIS的用例编排支持这种批量操作你可以用mode_block把一组操作包起来- mode_block: precision steps: - click: { resource_id: ... } - input: { resource_id: ..., text: ... } - click: { resource_id: ... } - mode_block: vision steps: - click: Flutter按钮 - click: 游戏区域这样模式切换只发生两次而不是每一步都切换。实测下来这种编排方式比逐步指定模式能快40%左右。6. 常见问题排查与实战避坑指南6.1 控件树模式典型问题速查问题现象可能原因排查方式解决方案控件树为空无障碍服务未启动检查辅助应用是否在运行重启辅助应用或重新授权定位到错误元素存在多个相同ID打印控件树查看重复节点增加层级约束或使用相对定位点击无响应控件被遮挡检查bounds是否被其他控件覆盖先滚动或关闭遮挡层获取超时界面持续动画查看是否有无限动画增加静默期或关闭动画文本匹配失败多语言或动态文案打印实际文本内容使用正则匹配或ID定位这个表格里的问题我基本都遇到过其中“控件树为空”是最让人抓狂的。有一次在真机集群上跑测试一半的设备控件树正常另一半死活获取不到。排查了半天发现是那些设备的系统版本较新对无障碍服务的后台限制更严格辅助应用被系统冻结了。解决办法是在辅助应用里加一个前台服务保活虽然有点重但确实管用。6.2 视觉模式识别失败的排查路径视觉模式的问题排查比控件树模式要复杂一些因为它涉及图像层面的因素。我总结了一个排查顺序按这个顺序走基本能定位到问题先看截图。ARTEMIS在每次视觉操作失败时会自动保存截图先打开截图看看目标元素在不在画面里。如果不在说明是页面没加载完或滚动位置不对跟识别无关。再看识别结果。ARTEMIS会输出识别到的所有元素及其置信度检查目标元素是否被识别到、置信度是多少。如果置信度低于阈值默认0.6说明模型对这个元素的识别不确定可以尝试降低阈值或调整截图质量。检查坐标转换。如果识别到了但点击位置不对大概率是坐标转换的问题。检查截图分辨率和设备分辨率是否一致缩放因子是否正确。检查遮挡和动效。如果识别和坐标都没问题但操作无效可能是元素被遮挡或正在动效中。尝试增加等待时间或先关闭弹窗。避坑技巧视觉模式对深色模式和浅色模式的识别效果可能不一样。如果你的应用支持主题切换建议在两种主题下都跑一遍视觉用例确保识别模型对两种配色都有足够的鲁棒性。我遇到过浅色模式下识别率95%、深色模式下掉到70%的情况后来在模型训练数据里补充了深色模式的样本才解决。6.3 双模式协同中的冲突与解决双模式协同工作时最常见的问题是状态不一致。比如控件树模式获取的界面状态是A切换到视觉模式后截图得到的状态是B两者不一致导致操作错乱。这种情况通常发生在界面正在变化的时候。ARTEMIS的处理方式是在模式切换时强制进行一次状态同步先等待界面稳定然后同时获取控件树和截图比较两者的关键特征比如页面标题、主要控件的位置如果差异超过阈值就重新等待。这个机制增加了切换的开销但避免了状态不一致导致的诡异失败。另一个冲突是操作竞争。比如控件树模式正在执行一个长按操作视觉模式同时发起了点击两个操作互相干扰。ARTEMIS通过操作队列来串行化所有操作确保同一时间只有一个操作在执行。这个设计牺牲了一点并发性但换来了稳定性我认为是值得的。7. 从架构到落地我的实际项目体会ARTEMIS的双模式架构说到底是在移动端碎片化现实下的一种务实选择。它没有追求“一套方案解决所有问题”的理想主义而是承认不同渲染方式需要不同的交互策略然后在架构层面把这种差异管理起来。这个思路我觉得比很多试图用单一模式打天下的方案要成熟得多。在实际项目中落地这套架构我的体会是前期投入在模式划分和用例编排上的时间会在后期回归测试中成倍地省回来。一开始你可能觉得要理解两种模式、要配置切换策略很麻烦但当你遇到一个页面改版导致控件树全变、而视觉模式兜底让用例继续跑通的时候就会觉得这些麻烦都是值得的。当然ARTEMIS也不是银弹。它的视觉模式在极端场景下比如高度动态的游戏界面、强反无障碍检测的应用仍然力不从心控件树模式在跨应用操作时也有局限。但对于大多数企业级移动应用的自动化测试需求来说这套双模式架构已经能覆盖90%以上的场景了。最后分享一个我在配置模式切换策略时的小技巧先用视觉模式跑一遍全量用例记录每个页面的识别成功率和耗时然后再针对性地把高成功率的页面切到控件树模式。这个顺序比反过来做要高效因为视觉模式不依赖控件树质量能先帮你摸清整个应用的页面构成再决定哪些页面值得用控件树模式去优化。这个思路我在三个项目里都用过每次都能省下不少试错时间。
阅读完成 · 觉得有帮助?
咨询建站