Files
meida/docs/真机闭环自动化测试-实践指南.md
xsl c9d13697a6 docs: 五轮多 Agent 评审迭代复盘 + 真机闭环自动化测试实践指南
- 复盘:编排设计、逐轮决策链、35 项修复全量清单、关键技术点、踩坑与复用流程
- 真机指南:闭环模型(注入/截图/dumpLayout/hilog 三通道)、命令手册、坐标库、
  安全访问选择器等 7 条踩坑、成本红线、标准测试脚本骨架
2026-08-30 23:22:02 +08:00

15 KiB
Raw Permalink Blame History

真机闭环自动化测试 · 实践指南

日期:2026-08-30 | 适用:Windows 开发机 + Git Bash + HarmonyOS 真机(本项目实测机:88Z9K26525009283,HarmonyOS,DevEco SDK 在默认安装路径) 本文是《五轮多Agent评审迭代-复盘与追溯.md》的姊妹篇:那篇讲"做了什么",这篇讲**"真机自动化闭环到底怎么搭、每条命令怎么用、哪些坑会让人白干一小时"**,目标是照抄即可复现。


0. 什么是本文说的"闭环"

注入输入(uitest uiInput) ──→ App/系统界面变化
      ↑                              │
      │                      观察三通道:
      │                      ① 截图 snapshot_display(视觉证据,留档)
      │                      ② UI 树 uitest dumpLayout(结构化文本,可 grep 坐标)
      │                      ③ hilog(App 内打点,判定逻辑走到哪一步)
      │                              │
判定(截图→视觉模型描述 / UI 树→精确文本+坐标 / hilog→时序事实)
      └──── 决定下一次注入 ←──────────┘

三通道缺一不可:截图给人看和留档,UI 树给机器精确定位(视觉模型对中文文案有幻觉,坐标和文字必须以 UI 树为准),hilog 区分"界面没变"是"代码没执行"还是"执行了但渲染没刷新"(本次迭代靠它定位了照片链 P0)。


1. 环境准备(一次性)

1.1 工具链路径

# 每个新 Git Bash 会话先执行(建议写进 ~/.bashrc)
export PATH="$PATH:/c/Program Files/Huawei/DevEco Studio/sdk/default/openharmony/toolchains"
export MSYS_NO_PATHCONV=1   # 关键!见 §5.1
  • hdc:<DevEco>/sdk/default/openharmony/toolchains/hdc
  • 构建门禁:cd /d/meida/app && cmd //c .build-gate.bat(产物 entry/build/default/outputs/default/entry-default-signed.hap,已签名)

1.2 设备

hdc list targets          # 应输出序列号,如 88Z9K26525009283

设备必须解锁亮屏。锁屏(PIN)会挡住一切交互注入——本次迭代 R1~R3 三轮测试全被 PIN 锁阻塞,只完成了"装包+启动+hilog 无崩溃"这层。屏幕熄灭后可用:

hdc -t <SN> shell "power-shell wakeup"           # 亮屏(无锁时直接到桌面)
hdc -t <SN> shell "uitest uiInput keyEvent 2"    # 上滑/唤醒手势(keyEvent 2 = 电源键语义场景之一,按设备实测)

有 PIN 的设备远程解不了锁(BouncerView 挡住),需要人手动解锁。这是当前方案的硬边界。

1.3 后端(App 登录/配额/报告链路需要)

后端跑在 WSL(Windows 侧 uv 管不了 WSL 建的 venv,必须进 WSL):

# 拉起(make up 起 PG/Redis → migrate → run;详见 meida_backend/README.md)
wsl -e bash -lc "cd /mnt/d/meida/meida_backend && make up && make migrate && make run"

# 健康检查(后端实际监听 0.0.0.0:8666)
wsl -e bash -lc "curl -s -m 2 http://127.0.0.1:8666/api/v1/health || echo DOWN"

真机连后端:真机访问开发机的局域网 IP(App 登录页可填服务地址;DEV_AUTH_ENABLED=true 时用 dev-token 登录)。Windows 侧验证转发是否通:curl http://127.0.0.1:8666/api/v1/health。

单测(不连库不发网络,安全):

wsl -e bash -lc "cd /mnt/d/meida/meida_backend && uv run --extra dev pytest tests/unit --no-cov -q"
# 注意 --extra dev:pytest 在 dev 依赖组里,不带会 spawn 失败

2. 核心命令手册

以下全部带 -t <SN>(多设备安全);单设备可省。<SN> = 88Z9K26525009283。

2.1 装包与启停(★ 有一个致命细节)

# 构建并安装
cd /d/meida/app && cmd //c .build-gate.bat
hdc -t <SN> install -r "D:\meida\app\entry\build\default\outputs\default\entry-default-signed.hap"

# 启动
hdc -t <SN> shell "aa start -a EntryAbility -b com.xiangsilian.app"

# ★★★ 验证新代码前必须重启进程:install -r 只替换包文件,不杀正在运行的进程!
#    aa start 对已运行的 App 只是拉到前台——你测的还是旧代码(R5 热修当场踩过)
hdc -t <SN> shell "ps -ef | grep xiangsilian | grep -v grep"   # 看进程启动时间戳甄别新旧
hdc -t <SN> shell "aa force-stop com.xiangsilian.app"          # 杀
hdc -t <SN> shell "aa start -a EntryAbility -b com.xiangsilian.app"   # 再启 → 这才是新包

# 杀图库(清"安全访问选择器"的残留蒙层,见 §5.3)
hdc -t <SN> shell "aa force-stop com.huawei.hmos.photos"

标准节奏:build → install -r → force-stop → start → 验证。

2.2 输入注入

hdc -t <SN> shell "uitest uiInput click 576 2340"              # 点击(像素坐标)
hdc -t <SN> shell "uitest uiInput longClick 576 2340"          # 长按(注意:是 longClick 不是 longPress)
hdc -t <SN> shell "uitest uiInput doubleClick 576 2340"
hdc -t <SN> shell "uitest uiInput swipe 576 2000 576 800 600"  # 滑动(velocity 200~40000)
hdc -t <SN> shell "uitest uiInput keyEvent Back"               # 返回键(也支持 Home/Power/数字)
hdc -t <SN> shell "uitest uiInput inputText 576 1200 hello"    # 对已聚焦输入框打字

打错命令时 uitest 会打印完整 usage(比猜语法快)。

2.3 观察通道一:截图

hdc -t <SN> shell "snapshot_display -f /data/local/tmp/shot.jpeg"
hdc -t <SN> file recv /data/local/tmp/shot.jpeg "D:\meida\.scratch\shot.jpeg"

截图按轮次留档(shots-rN/序号-场景.jpeg),既是证据也供事后分析(R4 测试挂掉后,58 张截图让接任 agent 零重复完成判定)。

2.4 观察通道二:UI 树(精确定位靠它)

hdc -t <SN> shell "uitest dumpLayout"          # 不带 --p,输出到 /data/local/tmp/layout_<id>.json
# 输出文件名在 stdout:"DumpLayout saved to:/data/local/tmp/layout_85596362629.json"
hdc -t <SN> file recv /data/local/tmp/layout_<id>.json 本地.json

注意:这台 ROM 上 uiautomator 不存在,用 uitest dumpLayout;--p 指定路径在该 ROM 上不生效(recv 报 no such file),让它默认落盘再按 stdout 报的文件名取。

解析(Git Bash 下用 node,比 python 省事——Windows 可能没装 python):

node -e "
const d=JSON.parse(require('fs').readFileSync('本地.json','utf8'));
function walk(n,out){ if(n&&typeof n==='object'){ if(n.text) out.push(n.text+' | '+(n.bounds||'')); for(const k in n) walk(n[k],out);} else if(Array.isArray(n)) n.forEach(x=>walk(x,out)); return out;}
console.log(walk(d,[]).filter(t=>!t.startsWith(' |')).slice(0,30).join('\n'));
"

bounds 格式 [x1,y1][x2,y2],点击坐标取中心 (x1+x2)/2, (y1+y2)/2。系统页面(相机、选择器)的节点可能整块渲染(照片网格只有一个大 Image 节点),此时只能靠截图估坐标。

2.5 观察通道三:hilog(逻辑时序的事实来源)

hdc -t <SN> shell "hilog -r"                          # 清缓冲(测前清一次,判定干净)
hdc -t <SN> shell "hilog -x | grep MEIDA_IMG | tail -5"   # 过滤本项目打点

App 侧要有打点体系才有这一通道。本项目 ImageCodec.ets 里 MEIDA_IMG 域 11 处打点(select 前后/URI 数量/解码/打包/各 stage 失败/超时放弃),照片链 P0 的定位与修复验证全靠它:

gallery: select begin
gallery: select end, 1 uri(s), first=file://media/Photo/…     ← 送达
gallery select not settled in 60000 ms, give up                ← 超时兜底触发
camera: pick end, resultUri length=63                          ← 拍照成功
jpeg: info 4000 x 3000 (120 ms) → pixelMap decoded → packed 284531 bytes   ← 压缩链通

新功能开发时先埋打点再上真机,是这套闭环能自动判定的前提。

2.6 崩溃监控

hdc -t <SN> shell "hilog | grep -iE 'com.xiangsilian.app.*(crash|FATAL|JS)'"

3. 视觉判定子环(AI 读图)与防幻觉纪律

截图拿回来后的判定链:

  1. Read 截图 → 得到 CDN URL
  2. analyze_image(URL, "具体问题") → 视觉模型描述(问坐标、问状态、问按钮位置)
  3. 交叉验证:涉及中文文案/精确状态时,以 UI 树 dump 的 text 字段为准——实测视觉模型会把「加载中」读成「错误」、把没勾选说成已勾选(R4/R5 各有一次教训)

提问要具体("第二列第一行的照片有没有被勾选?左上角有没有圆圈对勾?"),不要开放式("这页面有什么问题?")。


4. 已固化的坐标库(本机实测,换机/换分辨率需重测)

屏幕 1152×2520。坐标会随版本漂移,用前先 dumpLayout 校验。

场景 元素 坐标(中心)
首页 试衣间卡片 (440, 850)
首页 报告 Tab / 我的 Tab dumpLayout 取
试衣间 全身照·相册 / 拍照 (635, 1176) / (730, 1176)
试衣间 上衣·相册 / 拍照 (382, 1930) / (477, 1930)
试衣间 开始试穿 (576, 2306)
同意弹窗 不同意 / 同意并上传 (350, 1622) / (802, 1622)
系统相机 快门 (576, 2340)
系统相机 拍后确认 √ / 取消 ✕ (1045, 2345) / (100, 2345);不同布局下 √ ≈ (1038, 2360)
照片选择器 网格 3 列,列中心 x 192 / 576 / 960
照片选择器 第一行 y 975(有安全横幅时;横幅占位会推移)
照片选择器 关闭 ✕ (810, 212)
保存对话框 确认键(右上 ✓ 图标) dumpLayout 取(R3 已注记)

5. 踩坑全记录(每条都真实花过时间)

5.1 Git Bash 路径转义(最高频)

现象:hdc file recv /data/local/tmp/x.jpeg 报 Error opening file: no such file, path: C:/Program Files/Git/data/local/tmp/x.jpeg——MSYS 把 /data/... 当 Windows 路径转换了。引号包不住。 解法:会话开头 export MSYS_NO_PATHCONV=1。

5.2 install -r 不杀进程

见 §2.1。症状:新修复"无效"、行为与旧版一致。ps -ef 看进程启动时间戳即可识破。

5.3 系统选择器的"安全访问"模式(当前最大边界)

三个事实:

  1. 合成点击可能对选择器完全无效:照片既不勾选也不进预览(截图前后对比+UI 树无变化+hilog 无 select end 三方证实)。同为安全模式的系统保存对话框则可以点。疑似与 ROM 的反自动化保护或残留状态有关。
  2. picker 空结果收场后可能残留不可见蒙层,吞掉后续对选择器的一切注入;aa force-stop com.huawei.hmos.photos 可恢复(R5N3 记录,本次复现并验证了恢复手段)。残留的 filePicker 进程(kill -9 报 Operation not permitted)杀不掉,但它自 R4 测试成功期就存在,不是阻断因素。
  3. 结论:凡关键路径经过"安全访问选择器"的,闭环会在这里断,最后一步交人工(本次 R5 热修的预览刷新/压缩链就停在这一点,已在一分钟验收清单)。绕行思路(未验证):入口改用 photoAccessHelper.PhotoAccessHelper 授权+应用内自绘选择器,或用相机路径(A3 可自动化)覆盖测试场景。

5.4 相机自动化的模式面板

点快门附近区域可能拉出"拍照模式"抽屉挡住操作,且抽屉上的点击会切模式。解法:keyEvent Back 收起,重新对准坐标点快门。相机路径里"拍完→√确认"的坐标在同机不同布局下有两版(§4),点完必须截图确认真的出了相机。

5.5 PIN 锁与熄屏

熄屏打断的不只是测试——还打断了正在跑的 agent(R5 开发 agent 就是被用户熄屏操作打断成半成品)。长测试期间请保持亮屏解锁(开发者选项可设"充电时不锁定")。

5.6 hilog 缓冲冲刷

相机/图库会产生海量日志,把 MEIDA_IMG 冲掉。重要判定先 hilog -r 清缓冲再操作,操作完立即取;超时兜底类日志(60s 后才打)要等足时间再取。

5.7 agent 侧的坑

  • 上下文超限:R4 测试 agent 塞了 58 张截图+几十个 dump 后挂掉(Invalid string length)。纪律:单 agent 分析截图 ≤20 张、dump 只 grep 不整读、每完成一个场景就落盘中间结论。
  • 视觉幻觉:见 §3,一律与 UI 树交叉验证。
  • hdc 命令语法差异:longPress 不存在(是 longClick);uiautomator 不存在(是 uitest dumpLayout)——打错会打印 usage,照着改即可。

6. 红线与成本控制(写给下一轮测试 agent)

  • 换装/发型真实生成各 ≤1 次(Phase A 直连自有线上服务,虽不走 DeepSeek 计费但要省服务资源);失败不重试烧服务,记录跳过原因
  • 对话 ≤2 条(agent_chat 走 DeepSeek 真实计费,单条成本极低但有成本)
  • 绝不跑 make smoke(真实 DeepSeek 全链路,仓库 README 标注"唯一花钱的入口")
  • 后端集成测试(tests/integration)默认跳过,不强行开启(需要 PG/Redis)
  • 测试基建(.scratch/multiagent/checks/checks.mjs)可修,产品代码不可改;发现产品 bug 报告给下一轮,不越权修

7. 一轮标准测试的完整脚本骨架(可抄)

SN=88Z9K26525009283
export PATH="$PATH:/c/Program Files/Huawei/DevEco Studio/sdk/default/openharmony/toolchains"
export MSYS_NO_PATHCONV=1
H() { hdc -t $SN shell "$@"; }

# 0) 门禁
(cd /d/meida/app && cmd //c .build-gate.bat | tail -3)                       # 期待 BUILD SUCCESSFUL
wsl -e bash -lc "cd /mnt/d/meida/meida_backend && uv run --extra dev pytest tests/unit --no-cov -q | tail -2"
node /d/meida/.scratch/multiagent/checks/checks.mjs | tail -2                # 期待 28/28 PASS

# 1) 装新包并重启进程
hdc -t $SN install -r "D:\meida\app\entry\build\default\outputs\default\entry-default-signed.hap"
H "aa force-stop com.xiangsilian.app"; sleep 1
H "aa start -a EntryAbility -b com.xiangsilian.app"; sleep 4

# 2) 逐场景:清日志 → 注入 → 观察
H "hilog -r"
H "uitest uiInput click 440 850"; sleep 3                                    # 进试衣间
H "snapshot_display -f /data/local/tmp/s.jpeg"
hdc -t $SN file recv /data/local/tmp/s.jpeg ".scratch/scene.jpeg"
H "uitest dumpLayout"                                                        # stdout 给文件名 → recv → node 解析定位
H "hilog -x | grep MEIDA_IMG | tail -5"

# 3) 判定交叉验证 + 留档,进入下一场景……

8. 当前状态与待办

  • 已通:装包/重启/启动、页面导航与所有 App 自有 UI 交互、截图/dump/hilog 三通道、PDF 全链(含系统保存对话框)、飞行模式、杀 App 回看、登出重登、同意弹窗、断网错误态
  • 半通:系统相机(可自动拍+确认,偶发模式面板干扰)
  • 不通:照片选择器勾选(§5.3)——最后一公里人工,或改应用内自绘选择器
  • 改进方向:把 §7 骨架固化成 node 脚本(场景→步骤→断言三段式),配 MEIDA_IMG 式打点规范推广到报告域/对话域,即可从"agent 手操"升级为"一条命令跑回归"