做 App 自动化最头疼的不是"能不能点中",而是"为什么这次又点不中"。这篇文章沉淀了 App 端自动化在元素定位和执行稳定性上最实用的经验,全部来自真实项目的踩坑。
一、定位策略:优先级从稳定到脆弱
App 控件树比 Web 复杂得多(原生 + H5 + 自绘 UI 混合),定位策略直接决定脚本寿命。推荐按以下优先级选择:
| 优先级 | 策略 | 说明 | 脆弱性 |
|---|---|---|---|
| 1 | resource-id / accessibility id | 开发给控件起的稳定标识 | 低(需约定前缀规范) |
| 2 | content-desc(无障碍描述) | 专为 AT 准备的描述 | 低 |
| 3 | text 精确匹配 | 按钮/标签文案 | 中(多语言、动态文案会挂) |
| 4 | 层级路径 + 索引 | parent/child[2] |
高(布局微调即失效) |
| 5 | XPath 全文档查询 | 万能但慢 | 高,且性能差 |
实践约定:和开发约定 resource-id 前缀(如 com.app:id/btn_send),UI 改版时前缀语义不变,脚本就能活下来。XPath 只用于"实在没得选"的兜底,且禁止写超过 5 层的路径。
二、隐式等待:告别固定 sleep
固定 time.sleep(5) 是稳定性的头号杀手:网络快时白白浪费时间,网络慢时照样超时。正确姿势是显式条件轮询:
1 | from appium.webdriver.wait import WebDriverWait |
要点:
- 轮询间隔 0.5s 起,间隔太小会打满 UIAutomator 的 dump 开销,反而拖慢整体;
- 等待条件分三级:
存在 → 可见 → 可点击,点击前必须等到"可点击"; - 超时后的动作要显式:截图 + 断言失败,而不是默默 continue。
三、异常恢复:让失败可重试、可定位
1. 崩溃/ANR 自愈
App 崩溃后 driver 的 session 还活着但控件树已经没了,直接重试会连环失败。恢复顺序:
1 | def ensure_app_alive(driver, package, activity, max_relaunch=2): |
2. 弹窗拦截器
自动化最怕"计划外弹窗"(权限请求、升级提示、广告)。写一个统一的弹窗拦截,在每次关键操作前扫描:
1 | POPUP_RULES = [ |
3. 断言分级
- 硬断言:核心流程节点(消息发出、订单创建),失败即用例失败;
- 软断言:UI 细节(文案、颜色),失败只记录不中断,汇总后看趋势。
四、小结
稳定性三板斧:定位走稳定标识、等待走条件轮询、失败走显式恢复。这三条做到位,App 自动化脚本的周通过率能从 60% 提到 95% 以上。剩下的 5% 基本是产品自身的 bug——那正是自动化测试存在的意义。