尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
移动端自动化测试双模式架构:UI层级与图像识别融合实践
1. 移动端自动化测试为什么需要双模式这个设计移动端自动化测试这件事做过的人都清楚它跟Web端自动化完全是两个世界。Web端你只要管好浏览器驱动和页面元素定位就行但移动端你要面对的是不同厂商的ROM定制、不同版本的API差异、真机和模拟器的行为不一致、还有那些让人抓狂的弹窗和权限请求。我最早接触移动端自动化的时候用的是单模式的方案——一套脚本跑到底结果在模拟器上跑得好好的用例换到真机上就各种超时和元素找不到。ARTEMIS这个项目在架构设计上做了一个很关键的决定把移动端自动化拆成双模式来跑。这个双模式不是简单的两套脚本而是一套架构层面的抽象。具体来说它把移动端自动化的执行路径分成了两条一条是基于UI层级的交互模式另一条是基于图像识别的视觉模式。这两条路径共享同一套用例描述和断言逻辑但在底层执行引擎上完全独立。为什么要这么设计核心原因在于移动端测试场景的多样性。有些场景下UI层级树是完整可获取的比如原生Android应用你用UIAutomator或者AccessibilityService就能拿到完整的控件树这时候基于UI层级的操作又快又准。但有些场景下UI层级树要么拿不到要么拿到的信息残缺不全——比如Flutter渲染的界面、游戏引擎绘制的画面、或者某些做了反自动化处理的金融类应用。这时候你就得靠图像识别来定位和操作。我见过太多团队在这件事上走弯路要么死磕UI层级遇到拿不到层级的情况就束手无策要么全量上图像识别结果脚本跑得慢不说还特别容易受分辨率、主题、字体大小的影响。ARTEMIS的双模式架构本质上是在解决一个适配性问题——让合适的场景用合适的模式而不是一刀切。注意双模式不是让你同时跑两套而是根据被测应用的特征和测试目标选择最合适的执行路径。选错了模式后面全是坑。从架构层面看ARTEMIS把双模式抽象成了统一的执行器接口。上层用例只关心我要点击某个元素或者我要验证某个文本存在至于底层是用UI层级定位还是图像匹配定位用例层不需要知道。这种抽象带来的好处是当你的被测应用从原生切换到Flutter时你只需要切换执行器配置用例本身不用大改。这个设计思路其实借鉴了策略模式的思想。执行器接口定义了一组标准操作查找元素、点击、输入文本、滑动、截图、断言。每个具体执行器UI层级执行器、图像识别执行器各自实现这些操作。运行时根据配置决定用哪个执行器。这种设计让新增一种执行模式变得很容易——比如未来要加一个基于OCR的文本定位模式只需要实现一个新的执行器就行。2. UI层级模式的核心机制与适用边界2.1 UI层级树的获取与解析逻辑UI层级模式的基础是拿到被测应用的控件树。在Android上ARTEMIS通过AccessibilityService或者UIAutomatorServer来获取当前界面的层级结构。这个层级结构本质上是一个XML文档每个节点代表一个控件节点上挂着各种属性resource-id、text、class、content-desc、bounds、clickable、enabled等等。拿到这棵树之后ARTEMIS会把它解析成一个内存中的元素索引。这个索引不是简单的树形结构而是一个带缓存的扁平化映射。为什么要扁平化因为在实际操作中你很少需要按层级关系去找元素更多时候是按属性去找。比如找到所有text为登录的按钮这种查询在扁平化索引上做起来快得多。解析过程中有几个关键细节。第一个是节点去重。Android的层级树里经常出现嵌套的相同控件比如一个FrameLayout里面套了一个同样大小的LinearLayout两个节点的bounds完全一样。如果不做去重你可能会点到错误的节点。ARTEMIS的去重策略是如果父节点和子节点的bounds完全重合且父节点没有额外的语义信息比如没有text、没有resource-id就保留子节点丢弃父节点。第二个是可见性判断。层级树里有些节点是存在的但不可见比如被遮挡的、透明度为0的、或者宽高为0的。ARTEMIS在构建索引时会过滤掉这些节点但过滤逻辑不是简单的isVisible()调用而是综合判断bounds是否在屏幕范围内、宽高是否大于阈值、节点及其祖先节点的visibility属性。我实测下来这套过滤逻辑能过滤掉90%以上的无效节点但偶尔会误杀一些特殊场景下的控件比如某些自定义View的可见性判断不走标准API。第三个是属性归一化。不同厂商的ROM对控件属性的命名和取值有差异。比如有的ROM把resource-id放在resource-id属性里有的放在name属性里。ARTEMIS在解析时会做一层归一化把不同来源的属性映射到统一的字段上。这个归一化表是硬编码的但支持通过配置文件扩展。2.2 元素定位策略与优先级在UI层级模式下元素定位是核心操作。ARTEMIS支持多种定位策略按优先级从高到低排列定位策略匹配方式稳定性速度适用场景resource-id精确匹配最高最快原生控件有稳定idcontent-desc精确匹配高快无障碍标签完整的控件text精确/模糊匹配中快文本固定的按钮和标签class index组合匹配低中无id无text的容器控件xpath路径表达式低慢复杂层级关系的兜底方案实际使用中ARTEMIS的定位逻辑是按优先级依次尝试。比如你给了一个定位描述{id: login_btn, text: 登录}它会先找resource-id为login_btn的节点如果找到多个再用text过滤如果没找到id匹配的再退到只用text匹配。这种多级匹配策略的好处是容错性强但缺点是如果优先级设置不当可能会匹配到错误的元素。我踩过的一个坑是text匹配的模糊模式。ARTEMIS默认的text匹配是精确匹配但你可以开启模糊匹配。模糊匹配用的是包含关系比如你找登录它会匹配到登录/注册、立即登录、登录遇到问题等多个元素。如果这些元素同时存在脚本就会报找到多个匹配元素的错误。我的经验是能用id就不用text能用精确匹配就不用模糊匹配。只有在确实需要模糊匹配的场景下比如验证一段动态文本中包含某个关键词才开启模糊模式并且配合index或者父节点限定来缩小范围。另一个坑是动态id。有些应用会给控件生成动态的resource-id比如btn_123456每次启动都不一样。这种情况下resource-id定位就失效了。ARTEMIS的处理方式是支持正则匹配你可以写btn_\d来匹配这类动态id。但正则匹配的性能比精确匹配差不少所以只建议在确实需要的场景下使用。2.3 UI层级模式的失效场景UI层级模式不是万能的它在以下几类场景下会失效或者表现很差第一类是跨进程渲染的界面。比如Flutter、React Native、Unity这些框架它们在自己的渲染引擎里绘制界面暴露给AccessibilityService的层级树要么是空的要么只有最外层的一个容器节点。这种情况下你拿不到任何有意义的控件信息。第二类是游戏和视频播放器。这些应用通常用一个SurfaceView或者TextureView来绘制全部内容层级树里只有一个大节点没有任何子节点信息。第三类是做了反自动化处理的应用。有些金融类、安全类应用会检测AccessibilityService是否开启如果检测到就主动隐藏层级树信息或者返回伪造的层级结构。第四类是系统级弹窗和权限对话框。这些弹窗有时候不在应用的层级树里而是在系统层级需要特殊的处理方式。遇到这些场景UI层级模式就无能为力了必须切换到图像识别模式。ARTEMIS的双模式架构在这里体现了价值你不需要重写用例只需要在配置里切换执行器用例层完全无感。3. 图像识别模式的工程化落地细节3.1 模板匹配与特征点匹配的取舍图像识别模式的核心是在屏幕截图中找到目标元素的位置。ARTEMIS支持两种匹配算法模板匹配和特征点匹配。模板匹配的原理很简单你事先截取目标元素的图片作为模板然后在当前屏幕截图中滑动窗口计算每个位置的相似度取相似度最高的位置作为匹配结果。ARTEMIS用的是归一化互相关NCC算法对亮度变化有一定的鲁棒性。模板匹配的优点是速度快、实现简单缺点是对旋转、缩放、形变敏感。如果被测应用的界面在不同设备上有轻微的缩放差异模板匹配的准确率会明显下降。特征点匹配用的是SIFT或者ORB这类算法先提取模板和截图中的特征点然后做特征点匹配最后用RANSAC算变换矩阵。这种方法的优点是对旋转、缩放、形变都有很好的鲁棒性缺点是两个一是速度慢二是对于纯色或者纹理少的元素比如一个纯色按钮特征点提取效果很差可能根本提不出足够的特征点。ARTEMIS的策略是默认用模板匹配在模板匹配失败时自动降级到特征点匹配。这个降级逻辑是有条件的只有当模板图片的纹理丰富度超过阈值时才触发特征点匹配。纹理丰富度用图像的信息熵来衡量熵值低于阈值的模板直接跳过特征点匹配因为提不出特征点。我实测下来的经验是对于按钮、图标这类元素模板匹配足够了只要保证模板图片和实际截图的缩放比例一致。对于复杂的、有旋转可能的元素才需要特征点匹配。另外模板图片的选取很关键不要截取整个按钮而是截取按钮中有辨识度的局部比如按钮上的文字或者图标。这样匹配的准确率更高速度也更快。3.2 截图采集的时机与预处理图像识别模式的第一步是截图。ARTEMIS的截图采集有几个关键设计首先是截图时机。不是任何时候截图都能拿到稳定的画面。比如页面正在做转场动画、列表正在滚动、或者有加载中的进度条这时候截图会拿到模糊或者中间状态的画面。ARTEMIS的做法是在截图前先做稳定性检测连续截三帧如果三帧的差异小于阈值认为画面稳定取最后一帧作为输入如果差异大于阈值等待一段时间后重试最多重试N次。这个稳定性检测的逻辑看起来简单但实际调参很讲究。阈值设大了画面还在动就认为稳定了阈值设小了永远等不到稳定。我的经验是阈值设为画面平均像素差的5%左右重试间隔设为300ms最多重试10次。这个参数组合在大多数场景下都能工作。其次是截图预处理。原始截图不能直接拿去做匹配需要做几步预处理灰度化把RGB转成灰度图减少计算量。模板匹配在灰度图上做就够了颜色信息反而会引入噪声。降噪用高斯模糊去掉高频噪声。移动端截图经常有压缩伪影不降噪的话匹配分数会受影响。分辨率归一化如果模板图片和截图的尺寸不一致需要把截图缩放到模板的尺寸。ARTEMIS用的是双线性插值效果比最近邻插值好。预处理之后还要做感兴趣区域ROI裁剪。如果已知目标元素大概在屏幕的哪个区域可以只在这个区域做匹配大幅减少计算量。ARTEMIS支持在用例中指定ROI比如{roi: [0, 0, 1, 0.5]}表示只在屏幕上半部分找。3.3 匹配阈值的动态调整策略图像识别模式最头疼的问题是匹配阈值。阈值设高了匹配不到阈值设低了匹配到错误的位置。ARTEMIS的做法是动态调整阈值。具体来说ARTEMIS维护了一个匹配历史记录。每次匹配成功后记录下当时的匹配分数。如果连续多次匹配的分数都在某个范围内就把这个范围的中位数作为基准阈值。当新的匹配分数低于基准阈值时先不急着报失败而是做一次二次验证用特征点匹配再算一遍如果特征点匹配也失败才判定为失败。这个动态调整策略的好处是能适应不同设备的屏幕差异。比如同一套模板在A设备上匹配分数普遍是0.95在B设备上普遍是0.85动态阈值能自动适应这种差异。但缺点是引入了不确定性同样的用例在不同时间跑可能结果不一样。我的建议是对于关键断言不要依赖图像识别的结果而是用UI层级模式做断言图像识别只用来做操作。比如点击按钮用图像识别但验证点击后的页面是否正确用UI层级模式。注意图像识别模式下的断言天然比UI层级模式脆弱。能用UI层级做断言的地方尽量用UI层级。4. 双模式之间的切换与协同机制4.1 模式切换的触发条件与配置方式ARTEMIS的双模式切换不是自动的而是由用例配置显式指定。为什么不做自动切换因为自动切换的决策逻辑很难做对。你很难在运行时准确判断当前场景UI层级模式能不能用如果判断错了切换过去反而更慢更不准。配置方式是在用例的步骤级别指定执行器。比如steps: - action: click locator: mode: ui id: login_btn - action: click locator: mode: image template: assets/login_btn.png threshold: 0.85这种显式配置的好处是可预测。你知道每一步用的是什么模式出了问题也容易排查。缺点是配置成本高每个步骤都要指定模式。ARTEMIS的优化是支持默认模式在用例级别设置一个默认模式步骤级别不指定时用默认模式。这样对于大部分步骤都是同一种模式的用例配置量大幅减少。还有一种情况是同一个步骤需要两种模式协同。比如在图像识别找到的输入框里输入文本这个步骤需要先用图像识别定位输入框然后用UI层级模式做输入因为输入操作在UI层级模式下更可靠。ARTEMIS支持这种协同在步骤配置里同时指定定位模式和操作模式。4.2 共享用例描述层的设计双模式架构的关键在于用例描述层和执行层的分离。ARTEMIS的用例描述用的是一种领域特定语言DSL描述的是做什么而不是怎么做。比如- action: click target: 登录按钮 - action: input target: 用户名输入框 value: testuser - action: assert target: 欢迎文本 expect: 欢迎回来这个DSL里没有指定用UI层级还是图像识别只描述了操作意图。执行层根据配置的模式把登录按钮这个逻辑目标映射到具体的定位方式。在UI层级模式下登录按钮映射到{id: login_btn}在图像识别模式下登录按钮映射到{template: assets/login_btn.png}。这种映射关系维护在一个元素仓库里。元素仓库是一个YAML文件每个逻辑元素对应多种定位方式login_btn: ui: id: login_btn image: template: assets/login_btn.png threshold: 0.85这样做的好处是用例和定位方式解耦。当被测应用改版按钮的id变了你只需要改元素仓库不用动用例。当你要从UI层级模式切换到图像识别模式也只需要改元素仓库用例完全不动。4.3 两种模式的结果校验与交叉验证双模式架构还有一个隐藏价值交叉验证。在某些关键步骤上你可以同时用两种模式执行然后对比结果。如果两种模式的结果一致说明操作是可靠的如果不一致说明有问题需要人工介入。ARTEMIS支持配置验证模式在关键步骤上先用主模式执行再用辅模式验证。比如点击登录按钮先用UI层级模式点击然后用图像识别模式确认按钮确实被点击了按钮状态发生了变化。这种交叉验证能发现一些单模式发现不了的问题比如UI层级树更新延迟导致的点击了但没生效。但交叉验证的代价是执行时间翻倍。所以只建议在关键路径上使用不要全量开启。我的经验是登录、支付、提交订单这类关键操作开启交叉验证其他操作不开。5. 实际落地中遇到的典型问题与处理经验5.1 图像识别模式下的分辨率适配问题这是图像识别模式最常见的坑。同一套模板图片在1080P屏幕上匹配得好好的换到2K屏幕上就匹配不到了。原因是模板图片是在1080P下截的2K屏幕上的元素尺寸变大了模板匹配的滑动窗口对不上。ARTEMIS的处理方式是多分辨率模板。你可以在元素仓库里为同一个元素配置多个分辨率的模板login_btn: image: templates: - resolution: 1080x1920 path: assets/login_btn_1080.png - resolution: 1440x2560 path: assets/login_btn_1440.png运行时根据当前设备的分辨率选择对应的模板。如果找不到对应分辨率的模板就做等比缩放把模板缩放到当前屏幕的尺寸再匹配。等比缩放的精度不如原生模板但比不缩放好得多。我实测下来的经验是主流分辨率各准备一套模板覆盖80%以上的设备。剩下的20%用等比缩放兜底。另外模板图片的格式也有讲究用PNG不用JPG因为JPG的压缩伪影会影响匹配精度。5.2 UI层级模式下的元素定位超时处理UI层级模式下元素定位超时是最常见的失败原因。超时的原因有很多页面还没加载完、元素被遮挡、元素在滚动列表的不可见区域、或者元素根本就不存在。ARTEMIS的超时处理策略是分级超时短超时2秒用于已知会很快出现的元素比如点击按钮后的响应。中超时5秒用于需要网络请求的元素比如列表加载。长超时15秒用于冷启动后的首屏元素。超时后不是直接报失败而是做重试。重试的策略是先检查页面是否还在加载通过检测进度条或者loading控件如果还在加载就继续等如果加载完了但元素还没出现就滚动页面找找看如果滚动到底还没找到才报失败。这个重试逻辑能解决大部分超时问题但有一个坑有些元素的出现是条件性的。比如优惠券按钮只在有优惠券的时候才出现没有优惠券的时候永远等不到。这种情况下你需要用条件断言而不是强制等待。ARTEMIS支持optional标记标记为optional的元素超时后不报失败而是跳过。5.3 双模式混用时的状态同步问题双模式混用时最大的问题是状态同步。比如你用UI层级模式点击了一个按钮页面跳转了然后你用图像识别模式去找新页面的元素。如果UI层级模式的点击操作还没完全生效页面还在转场动画中图像识别模式截到的图就是中间状态的画面匹配会失败。ARTEMIS的解决方案是操作屏障。每次操作完成后插入一个屏障等待页面稳定后再执行下一步。屏障的实现方式是连续截三帧如果三帧差异小于阈值认为页面稳定。这个逻辑和前面说的截图稳定性检测是一样的但屏障是全局的不限于图像识别模式。操作屏障的代价是每一步都增加等待时间。ARTEMIS的优化是自适应屏障对于已知会触发页面跳转的操作比如点击导航按钮插入完整屏障对于不会触发跳转的操作比如输入文本插入轻量屏障只等待500ms。5.4 元素仓库的维护与版本管理元素仓库是双模式架构的核心资产但也是最容易腐化的部分。应用改版、UI调整、文案变更都会导致元素仓库失效。ARTEMIS在元素仓库的维护上做了几件事第一是元素仓库的版本管理。元素仓库文件纳入Git管理每次修改都有记录。当用例失败时可以快速定位到是哪个版本的元素仓库引入的问题。第二是元素仓库的自动检测。ARTEMIS提供了一个命令行工具可以扫描元素仓库检测哪些元素的定位方式在当前应用版本上已经失效。这个工具会输出一个报告列出失效的元素和建议的修复方式。第三是元素仓库的复用。不同用例之间共享元素仓库避免重复定义。ARTEMIS支持元素仓库的继承和覆盖基础元素仓库定义通用元素项目元素仓库继承基础仓库并覆盖项目特有的元素。我个人的经验是元素仓库的维护要趁早。不要等到用例大面积失败了才去修而是每次应用改版后主动跑一遍元素检测工具把失效的元素提前修掉。另外元素仓库的命名要有规范比如用页面名_元素名的格式方便查找和管理。6. 从单模式到双模式的迁移路径建议如果你现在的移动端自动化还是单模式想迁移到双模式我的建议是渐进式迁移不要一次性全量切换。第一步是引入元素仓库。即使你还在用单模式也先把元素定位信息从用例里抽出来放到元素仓库里。这一步的收益是立竿见影的用例的可维护性大幅提升改定位方式不用动用例。第二步是在单模式内支持多种定位策略。比如你原来只用resource-id定位现在加上text定位、xpath定位作为兜底。这一步的收益是定位成功率提升但还不涉及模式切换。第三步是引入第二种模式作为补充。比如你原来只用UI层级模式现在在UI层级模式失效的场景下用图像识别模式兜底。这一步的关键是不要改变现有用例的结构只是在执行层增加一个降级路径。第四步是在关键路径上启用双模式交叉验证。这一步的收益是发现一些隐藏的问题但代价是执行时间增加。建议只在核心用例上开启。整个迁移过程可能需要几周到一个月的迭代但每一步都有明确的收益不会出现迁移到一半发现走不通的情况。我见过一些团队一上来就搞全量双模式结果因为图像识别的稳定性问题用例失败率飙升最后又退回单模式。渐进式迁移虽然慢但稳。提示迁移过程中保持旧模式的用例继续跑新模式的用例并行跑。对比两者的结果确认新模式没有引入新的问题后再逐步切换。最后分享一个我在实际项目中总结的小技巧给每个用例打上模式标签。比如ui表示这个用例适合UI层级模式image表示适合图像识别模式both表示两种模式都支持。这样在跑回归的时候可以根据当前被测应用的特征选择性地跑对应标签的用例避免在不适合的模式上浪费时间。这个标签体系看起来简单但在用例数量上去之后能大幅提升回归效率。
RELATED

相关推荐

多账号运营防关联指南:指纹浏览器选型与部署实践

多账号运营防关联指南:指纹浏览器选型与部署实践

做多账号运营这几年,我最大的感受是:账号本身不怕多,怕的是所有账号在平台眼里“长一张脸”。注册十个账号不难,难的是十个账号各自拥有独立且稳定的浏览器环境——IP、时区、语言、Canvas指纹、WebGL参数全部各不相同&#xff0c…

📅 2026/10/22 20:20:22
GpuCloudSim初探:GPU资源调度与干扰建模仿真框架

GpuCloudSim初探:GPU资源调度与干扰建模仿真框架

1. 项目概述:这不是一个“跑通Demo”的简单任务,而是一次对GPU资源调度底层逻辑的系统性解剖你点开这个标题,大概率是刚接触云仿真、正在做分布式计算或异构资源调度相关课题的研究者,也可能是某高校实验室里被导师扔来一份CloudS…

📅 2026/10/22 20:20:22
C语言指针完全指南:从内存地址到链表实战,避开野指针与悬垂指针

C语言指针完全指南:从内存地址到链表实战,避开野指针与悬垂指针

每个学C的人都会在指针上栽一次。我见过太多新手在变量声明那几天“突然失明”:代码编不过去、运行时莫名其妙崩溃、打印出的地址跟想象完全对不上。指针这个东西,说难也难,说简单也简单——你只要搞明白了一件事: 所有指针问题的…

📅 2026/10/22 20:20:22
MORE NEWS

更多资讯

📰

Rust正成为AI基础设施的底层新标准

1. 项目概述:这不是技术风向标,而是基建层的静默迁移“3个信号:AI基建正在转向Rust”——这句话最近在多个技术社区高频出现,但很多人读完标题只留下模糊印象:哦,Rust又火了?AI圈开始用Rust了&a…

📰

Rust为何成为AI基础设施的确定性选择

1. 这不是技术风潮,是基建层的静默迁移最近在几个核心开源项目的更新日志里反复看到同一个现象:原本用Go写的CLI工具,新版本悄悄换成了Rust;某知名云原生中间件的v2.0架构图里,底层数据平面模块标注着“Rust重写中”&a…

📰

FreeRTOS任务通知实战详解:内核原理、API与避坑指南

裸机编程切到RTOS之后,任务之间的通信和同步永远是躲不开的坎。前面聊过队列、信号量、互斥锁、事件组,这次把FreeRTOS任务通知(Task Notification)单独拎出来讲透。原因很简单:任务通知是FreeRTOS里最容易用错、也最容…

📰

数据服务监控运维实战:从指标体系到告警治理与故障排查

周末凌晨两点,手机震了。第一反应是“数据服务挂了”。打开电脑看了下,果然,某张核心报表的数据产出时间已经超过SLA两小时,下游三个业务方连着发来问询。这种场景,做过大数据运维的人都不会陌生。数据服务的监控与运维…

📰

Verilog实现FPGA密码锁:矩阵键盘与状态机设计实战

说实话,这几年接触了不少想入门FPGA的朋友,如果你问哪个项目能一口气把Verilog的核心基本功串起来,我通常会推荐电子密码锁。这个项目看着不起眼,却把矩阵键盘扫描、按键消抖、状态机设计、动态显示刷新、外设控制这些数字逻辑里的…

📰

AI大模型开发转行指南:从学习路线到项目实战的完整路径

作为一个半路出家做AI大模型开发的人,我太清楚“转行”这两个字背后藏着多少犹豫和焦虑了。三年前我还在一家传统软件公司写着业务系统,每天跟增删改查打交道,后来靠着下班后的持续学习和几个拿得出手的项目,硬是切到了大模型开发…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬