06-鸿蒙系统 uitest UI 自动化指南
摘要:本文系统讲解鸿蒙 HarmonyOS 的命令行 UI 自动化工具
uitest。涵盖uiInput事件注入(点击/滑动/输入/按键)、dumpLayout控件树解析与基于属性的精准定位、uiRecord录制回放、等待与断言机制、多设备 CI/CD 集成、常见报错排查等。配套可直接复用的 PowerShell 自动化脚本模板,助你从"操作脚本"进阶到"可落地的自动化工程"。关键词:鸿蒙测试、HarmonyOS、uitest、UI 自动化、dumpLayout、控件树、hdc、回归测试、uiInput
适用对象:想做控件级、确定性 UI 自动化(而非纯随机压测)的新人
文档定位:uitest 命令速查 + 控件树怎么查 + 等待/断言机制 + 直接抄的自动化脚本
配套系列:hdc 环境配置(第1弹)· wukong 测试(第2弹)· hilog 使用指南(第3弹)· keycodeType 详解(第4弹)· faultlog 崩溃日志分析(第5弹)· DevEco Studio 图形化测试(第7弹)。同系列文章均已在个人主页发布,可在主页目录查看。
一、uitest 是什么(30 秒理解)
uitest 是鸿蒙 UI 测试框架的命令行入口,提供控件级的 UI 操作能力(点击、滑动、输入、截图、查控件树、录制回放)。
和 keyevent / wukong 的区别(选型必看):
| 工具 | 粒度 | 特点 | 适用 |
|---|---|---|---|
input keyevent | 按键 | 只能发按键,最粗 | 简单控键(第4弹) |
wukong | 随机 | 模糊/Monkey 式压测,不可控 | 稳定性随机压测(第2弹) |
uitest(命令行) | 控件/坐标 | 精确、可录制、可查控件树 | 临时验证、冒烟、shell 串自动化 |
一句话:wukong 乱点找崩溃,uitest 精准点做流程。 要跑"登录→下单→退出"这种固定脚本,用 uitest。
命令行 uitest vs ArkTS UiTest 框架(选型补充)
新手常问:什么时候用命令行 uitest,什么时候写 ArkTS 测试用例?两者定位不同:
| 维度 | 命令行 uitest | ArkTS UiTest(@ohos.uitest) |
|---|---|---|
| 上手成本 | 低,shell 即可 | 高,需写 TS + 编译部署 |
| 定位方式 | 坐标 / dump 后解析 JSON | By.text/id/className 定位器,抗分辨率 |
| 断言/报告 | 弱(需自己拼 grep/sleep) | 强(内置 assert + 报告) |
| 等待机制 | 需手写轮询 | 内置 driver.wait |
| 可维护性 | 低(裸坐标易碎) | 高(用例可版本管理) |
| 适用场景 | 临时验证、冒烟、CI 串脚本、无源码场景 | 正式回归套件、复杂流程、长期维护 |
选型建议:5 条命令以内的快速验证 → 命令行 uitest;超过 20 步、需长期维护的回归套件 → 写 ArkTS 用例(见第7弹 DevEco 图形化测试)。本篇聚焦命令行。
二、前提条件
# 1. hdc 已配通(见第1弹),设备开 USB 调试并连上
hdc list targets # 能看到设备
# 2. 确认 uitest 可用
hdc shell uitest --version
# 3.(部分版本/老系统)无响应时,先使能 UI 测试框架
hdc shell param set persist.ace.testmode.enabled 1
# 官方 HarmonyOS 指南未强制要求此步,但 OpenHarmony/部分版本需要,
# 命令无响应时优先试这一条。
# 4. 查屏幕分辨率/DP(写坐标适配脚本时必用)
hdc shell hidumper -s RenderService -a screenInfo
# 输出示例:width=1080 height=2400 density=3.0
关于 testmode 开关:
persist.ace.testmode.enabled是持久化参数,重启后仍生效。- 测试机:保持
1即可,无副作用。- 生产/外发设备:测完建议关闭,恢复
param set persist.ace.testmode.enabled 0,避免控件树暴露给未授权工具。- 查当前值:
hdc shell param get persist.ace.testmode.enabled。
注意:命令是
uitest(全小写主命令),子命令大小写为uiInput/dumpLayout/screenCap/uiRecord(骆驼峰)。社区常写小写uiinput部分版本也能兼容,但以官方大小写为准。
三、命令总览
| 子命令 | 用途 |
|---|---|
uitest uiInput <操作> | 注入 UI 事件(点击/滑动/输入/按键) |
uitest dumpLayout | 获取当前界面控件树(JSON) |
uitest screenCap | 截图 |
uitest uiRecord | 录制/回放界面操作 |
uitest start-daemon | 拉起测试进程(一般自动拉起,手动用于排查) |
uitest --version | 版本信息 |
API 版本兼容性总览(一张表)
文中零散出现的 API 版本要求汇总在此,便于设备选型时核对:
| 命令/参数 | 最低 API | 备注 |
|---|---|---|
uitest 主命令 | API 9+ | OpenHarmony 起支持 |
uitest uiInput click/swipe/... | API 9+ | 基础注入 |
uitest uiInput text <文本> | API 18+ | 获焦输入(无需坐标) |
uitest uiInput inputText x y <文本> | API 9+ | 坐标输入 |
uitest uiInput dircFling | API 9+ | 方向滑动 |
uitest dumpLayout -a(扩展属性) | API 10+ | 颜色/字体等 |
uitest dumpLayout -w <windowId> | API 10+ | 指定窗口 |
uitest screenCap -d <displayId> | API 20+ | 多屏指定 |
uitest uiRecord record -W false | API 20+ | 仅坐标,不存控件 |
uitest uiRecord record -l | API 20+ | 每操作存布局快照 |
uitest uiRecord replay | API 10+ | 回放录制脚本 |
设备 API 版本查询:
hdc shell param get const.ohos.apicompatibility.version
四、uiInput 注入详解(最核心)
4.1 点击类(坐标)
hdc shell uitest uiInput click 100 100 # 单击 (x,y)
hdc shell uitest uiInput doubleClick 100 100 # 双击
hdc shell uitest uiInput longClick 100 100 # 长按
4.2 滑动 / 拖拽类
# 慢滑:起点(10,10) → 终点(200,200),速度 500 px/s
hdc shell uitest uiInput swipe 10 10 200 200 500
# 拖拽(同签名)
hdc shell uitest uiInput drag 10 10 100 100 500
# 快滑/抛滑
hdc shell uitest uiInput fling 10 10 200 200 500
# 方向滑动:0左 1右 2上 3下
hdc shell uitest uiInput dircFling 2 # 上滑
hdc shell uitest uiInput dircFling 0 500 # 左滑,速度500
速度参数
swipeVelocityPps_默认 600,范围 200~40000。
4.3 文本输入
# 在指定坐标的输入控件里输入
hdc shell uitest uiInput inputText 100 100 hello
# 当前已获焦的输入框直接输入(API 18+)
hdc shell uitest uiInput text hello
⚠️ 密码输入安全:直接把密码写在命令里会留在 shell history 和 hilog 里。生产测试建议用环境变量或临时文件:
# PowerShell:密码不落 history 明文 $pwd = Read-Host "请输入密码" -AsSecureString $plain = [Runtime.InteropServices.Marshal]::PtrToStringAuto( [Runtime.InteropServices.Marshal]::SecureStringToBSTR($pwd)) hdc shell uitest uiInput text $plain $plain = $null详见第十七节"安全注意事项"。
4.4 按键 / 组合键 ⚠️ 和第4弹"两套体系"呼应
hdc shell uitest uiInput keyEvent Home # 名称方式(推荐)
hdc shell uitest uiInput keyEvent Back
hdc shell uitest uiInput keyEvent Power
# 数字方式:用的是 **ArkTS KeyCode 枚举值**(不是 input keyevent 的底层数字!)
hdc shell uitest uiInput keyEvent 2038 # = KEYCODE_V(单键)
hdc shell uitest uiInput keyEvent 2072 2038 # = Ctrl+V(组合键:Ctrl + V)
hdc shell uitest uiInput keyEvent 2047 2038 # = Shift+V(大写 V)
⚠️ 关键坑:
uitest uiInput keyEvent的 keycode 走应用层 ArkTS 枚举(Home=1 / Back=2 / V=2038 / Ctrl=2072),而input keyevent走底层 Android 数字(Home=3 / Back=4)。两者不一样!详见同系列「keycodeType 详解与 hdc 发送按键」一文。名称(Home/Back/Power)最不容易错,优先用名称。
keyEvent 常用名称/值速查(节选自第4弹)
| 名称 | ArkTS 值 | 说明 | 名称 | ArkTS 值 | 说明 |
|---|---|---|---|---|---|
Home | 1 | 主屏 | Enter | 2054 | 回车 |
Back | 2 | 返回 | Del | 2055 | 退格 |
Search | 9 | 搜索 | Space | 2050 | 空格 |
VolumeUp | 16 | 音量+ | Tab | 2049 | Tab |
VolumeDown | 17 | 音量- | Menu | 2067 | 菜单 |
Power | 18 | 电源 | Escape | 2070 | Esc |
Camera | 19 | 拍照 | DPAD_CENTER | 2016 | 确定 |
| 字母 A~Z | 2017~2042 | 如 V=2038 | 数字 0~9 | 2000~2009 | 如 1=2001 |
| 修饰键 | Ctrl=2072 / Shift=2047 / Alt=2073 | 组合键用:keyEvent 2072 2038 = Ctrl+V |
完整清单见同系列「keycodeType 详解与 hdc 发送按键」一文的 KeyCode 枚举详解章节。组合键写法:
keyEvent <修饰键值> <主键值>,最多支持多修饰键。
4.5 多指/复杂手势(命令行能力边界)
命令行 uiInput 只支持单指操作。以下场景命令行做不到,需转向 ArkTS UiTest 框架:
| 手势 | 命令行支持 | 替代方案 |
|---|---|---|
| 单指点击/滑动/拖拽 | ✅ | uiInput click/swipe/drag |
| 长按 / 双击 | ✅ | uiInput longClick/doubleClick |
| 双指缩放(pinch/zoom) | ❌ | ArkTS driver.pinch |
| 多指点击 / 三指手势 | ❌ | ArkTS 多 Finger API |
| 路径滑动(如解锁图案) | ❌ | ArkTS 自定义 gesture |
| 连续手势编排 | ❌ | ArkTS 或 uiRecord 录制后回放 |
一句话:命令行管单指,多指找 ArkTS。 复杂手势可先
uiRecord record录制,再replay回放(见第七节)。
五、dumpLayout 获取控件树(找控件坐标/属性)
做精确自动化前,先 dump 当前界面控件树,拿到每个控件的 坐标边界、id、文本、类型,再决定点哪。
# 导出控件树到文件(再 hdc file recv 拉回 PC 看)
hdc shell uitest dumpLayout -p /data/local/tmp/layout.json
# 扩展属性(背景色/内容/字体色/字号等),与 -i 互斥
hdc shell uitest dumpLayout -a -p /data/local/tmp/layout_full.json
# 指定窗口(windowId 用 hidumper 查,见第八节)
hdc shell uitest dumpLayout -w <windowId> -p /data/local/tmp/w.json
5.1 控件树字段说明
关键字段(来自 dumpLayout JSON 与录制数据示例):
| 字段 | 含义 | 示例 |
|---|---|---|
type / W1_Type | 控件类型 | Button / Text / Image |
text / W1_Text | 控件文本 | "确认" |
id / W1_ID | 控件 id | btn_confirm |
bounds / W1_BOUNDS | 边界坐标 | [0,0][100,50](左上-右下) |
clickable | 是否可点击 | true/false |
enabled | 是否可用 | true/false |
checked | 是否选中 | true/false |
⚠️ 字段命名注意:dumpLayout JSON 默认输出
type/text/id/bounds(小写驼峰,在attributes对象里);uiRecord read输出的 CSV 用W1_Type/W1_Text/W1_ID/W1_BOUNDS前缀。两者字段对应但命名不同,解析时以实际输出为准。
5.2 真实 layout.json 片段(脱敏示例)
{
"attributes": {
"type": "RootNode",
"bounds": "[0,0][1080,2400]",
"clickable": false,
"enabled": true
},
"children": [
{
"attributes": {
"type": "Column",
"bounds": "[0,100][1080,800]",
"id": "",
"text": ""
},
"children": [
{
"attributes": {
"type": "Button",
"id": "btn_confirm",
"text": "确认",
"bounds": "[440,1100][640,1200]",
"clickable": true,
"enabled": true
},
"children": []
},
{
"attributes": {
"type": "TextInput",
"id": "input_account",
"text": "",
"bounds": "[100,900][980,1000]",
"clickable": true
},
"children": []
}
]
}
]
}
拿到
bounds后,取中心(x1+x2)/2, (y1+y2)/2作为click坐标,就能精准点控件,不用肉眼猜坐标。例如[440,1100][640,1200]→ 中心(540, 1150)。
5.3 基于属性定位(jq / grep 解析,抗分辨率)
裸坐标脚本在不同分辨率设备上会全部偏移。推荐按属性查控件再算中心,这是从"操作脚本"走向"自动化"的关键一步:
# 方法1:用 jq 按文本找按钮,输出 bounds
hdc shell uitest dumpLayout -p /data/local/tmp/l.json
hdc file recv /data/local/tmp/l.json ./l.json
# jq 递归遍历,匹配 text=="确认" 的节点
jq -r '.. | objects | .attributes? | select(.text=="确认") | .bounds' l.json
# 输出:[440,1100][640,1200]
# 方法2:按 id 找(最稳,不受语言/文本变化影响)
jq -r '.. | objects | .attributes? | select(.id=="btn_confirm") | .bounds' l.json
# 方法3:没有 jq,用 grep(粗略)
grep -oE '"text":"确认"[^}]*"bounds":"\[[0-9,]+\]\[[0-9,]+\]"' l.json
# 方法4:PowerShell 原生解析(Windows 无 jq 时)
$j = Get-Content l.json -Raw | ConvertFrom-Json
$btn = $j.children[0].children | Where-Object { $_.attributes.text -eq "确认" }
$btn.attributes.bounds
定位优先级:
id(最稳) >text(次稳) >type+bounds(兜底) > 裸坐标(最脆)。能用 id 就别用坐标。
完整属性定位闭环:
# 一行命令拿到控件中心坐标(jq + awk 算中心)
hdc shell uitest dumpLayout -p /data/local/tmp/l.json
hdc file recv /data/local/tmp/l.json ./l.json
BOUNDS=$(jq -r '.. | objects | .attributes? | select(.id=="btn_confirm") | .bounds' l.json)
# BOUNDS="[440,1100][640,1200]" → 解析出中心
X=$(echo $BOUNDS | grep -oE '[0-9]+' | sed -n '1p;3p' | awk '{s+=$1} END{print int(s/2)}')
Y=$(echo $BOUNDS | grep -oE '[0-9]+' | sed -n '2p;4p' | awk '{s+=$1} END{print int(s/2)}')
hdc shell uitest uiInput click $X $Y
六、screenCap 截图
hdc shell uitest screenCap # 默认存 /data/local/tmp/时间戳.png
hdc shell uitest screenCap -p /data/local/tmp/1.png # 指定路径
hdc shell uitest screenCap -d <displayId> # 多屏指定屏幕(API 20+)
# 拉回 PC
hdc file recv /data/local/tmp/1.png ./1.png
截图常用于测试留证和断言辅助(界面是否到达预期)。CI 流水线建议按用例名+时间戳归档:
$ts = Get-Date -Format "yyyyMMdd_HHmmss" hdc shell uitest screenCap -p /data/local/tmp/case01_$ts.png hdc file recv /data/local/tmp/case01_$ts.png ./reports/case01_$ts.png
七、uiRecord 录制回放(不会写命令也能自动化)
# 开始录制(手动在设备上操作,Ctrl+C 结束,存 /data/local/tmp/record.csv)
hdc shell uitest uiRecord record
# 读取并打印录制内容
hdc shell uitest uiRecord read
# 仅记录坐标(不存控件信息,API 20+)
hdc shell uitest uiRecord record -W false
# 每次操作同时存布局快照(API 20+)
hdc shell uitest uiRecord record -l
7.1 回放录制脚本
# 回放默认录制文件
hdc shell uitest uiRecord replay
# 回放指定文件
hdc shell uitest uiRecord replay -p /data/local/tmp/record.csv
录制数据含
OP_TYPE(click/doubleClick/longClick/drag/swipe/fling)、fingerList(控件属性)等,可用于复盘操作序列或转成自动化脚本。
7.2 录制 CSV 转脚本(思路)
uiRecord read 输出的 CSV 每行是一次操作,关键字段:
| 字段 | 含义 | 示例 |
|---|---|---|
OP_TYPE | 操作类型 | click / swipe |
POS_X / POS_Y | 坐标 | 540,1150 |
fingerList | 控件属性快照 | 含 text/id/bounds |
转换思路:用脚本读 CSV,把每行翻译成 uitest uiInput 命令,并在操作间插入 sleep:
# PowerShell:record.csv → 可执行 .ps1 脚本
Import-Csv record.csv | ForEach-Object {
switch ($_.OP_TYPE) {
"click" { "hdc shell uitest uiInput click $($_.POS_X) $($_.POS_Y)" }
"swipe" { "hdc shell uitest uiInput swipe $($_.POS_X) $($_.POS_Y) $($_.END_X) $($_.END_Y) 500" }
default { "# 未识别操作: $($_.OP_TYPE)" }
}
"Start-Sleep -Milliseconds 800 # 操作间隔,防时序错乱"
} | Set-Content replay.ps1
⚠️ 回放限制:录制依赖当时分辨率和时序,跨设备/跨分辨率回放可能偏移;操作太快时回放可能丢步。建议回放脚本中每步加
sleep 0.5~1s。
八、启动应用与窗口定位(aa/bm/hidumper 联动)
自动化第一步通常是"打开目标 App",uitest 本身不带启动命令,需联动 aa(Ability Assistant)和 bm(Bundle Manager):
# 1. 查已安装应用包名
hdc shell bm dump -n com.xxx.xxx # 看 ability 信息
# 或列所有包
hdc shell bm dump -a
# 2. 启动应用(指定 ability 名 + 包名)
hdc shell aa start -a EntryAbility -b com.xxx.xxx
# 3. 强制停止应用(用例间清理)
hdc shell aa force-stop com.xxx.xxx
# 4. 查当前前台窗口 windowId(dumpLayout -w 用)
hdc shell hidumper -s WindowManager -a "-a"
# 或
hdc shell hidumper -s Window | grep -i "windowId"
能力边界:
uitest只负责"操作已显示的界面",启动/停止应用、查窗口 ID 用 aa/bm/hidumper。完整自动化脚本通常是aa start→sleep 2→uitest uiInput ...的组合。
九、等待与断言机制(自动化的灵魂)
没有等待和断言的脚本只是"操作记录",不是"测试"。这两项是命令行 uitest 自动化的核心补强。
9.1 等待机制(轮询控件出现)
界面跳转、列表加载都有延迟,连续 uiInput 之间必须 sleep 或轮询:
# 简单等待(PowerShell)
Start-Sleep -Seconds 2
# 进阶:轮询等待目标控件出现(最多 10 秒,每秒查一次)
for ($i=1; $i -le 10; $i++) {
hdc shell uitest dumpLayout -p /data/local/tmp/l.json
hdc file recv /data/local/tmp/l.json ./l.json 2>$null
if (Select-String -Path l.json -Pattern '"text":"登录成功"' -Quiet) {
Write-Host "控件已出现,耗时 ${i}s"
break
}
Start-Sleep -Seconds 1
}
if ($i -gt 10) { Write-Host "⚠️ 等待超时"; }
等待策略:
- 短操作(点击即响应):
sleep 0.5~1s- 跳转/加载:轮询 dumpLayout,超时 10~15s
- 网络/启动:超时 20~30s
- 不要写死长 sleep(如
sleep 10),既慢又不稳;用轮询代替。
9.2 断言机制(验证操作结果)
| 断言类型 | 方法 | 示例 |
|---|---|---|
| 控件文本 | dumpLayout 后 grep | grep "text":"登录成功" |
| 控件存在 | grep 控件 id | grep "id":"btn_logout" |
| 控件状态 | grep enabled/checked | grep "checked":true |
| 截图对比 | screenCap + 人工/工具 | 留证供抽检 |
| 隐式断言 | hilog 抓异常关键词 | hilog -L E | grep -iE "crash|exception" |
断言闭环示例(登录后验证):
# 操作 + 等待 + 断言 三段式
hdc shell uitest uiInput click 540 1150 # 点登录
# 等待并断言"登录成功"文本出现
$pass = $false
for ($i=1; $i -le 15; $i++) {
hdc shell uitest dumpLayout -p /data/local/tmp/l.json
hdc file recv /data/local/tmp/l.json ./l.json 2>$null
if (Select-String -Path l.json -Pattern '登录成功' -Quiet) {
$pass = $true; break
}
Start-Sleep -Seconds 1
}
if ($pass) { Write-Host "PASS: 登录成功" }
else {
Write-Host "FAIL: 登录失败,截图留证"
hdc shell uitest screenCap -p /data/local/tmp/fail.png
hdc file recv /data/local/tmp/fail.png ./fail_$(Get-Date -Format HHmmss).png
# 联动 hilog 抓异常(第3弹)
hdc shell hilog -x | Select-String -Pattern "Exception|Crash" -CaseSensitive:$false
}
⚠️ hilog 作为断言是隐式的——崩溃一定会抛异常日志,但异常日志不代表一定崩。需结合 faultlog(第5弹)确认。
十、实战模板(直接抄)
# === 模板1:启动应用 → 查控件 → 点按钮(属性定位 + 等待)===
hdc shell aa start -a EntryAbility -b com.xxx.xxx
Start-Sleep -Seconds 2 # 等应用启动
hdc shell uitest dumpLayout -p /data/local/tmp/l.json
hdc file recv /data/local/tmp/l.json ./l.json
# jq 按 id 找"确认"按钮,算中心(jq 需另行安装;无 jq 见 5.3 的 grep/awk 方案)
$BOUNDS = jq -r '.. | objects | .attributes? | select(.id=="btn_confirm") | .bounds' l.json
# (中心点解析略,见 5.3)
hdc shell uitest uiInput click 540 1150
# === 模板2:登录流程(输入账号密码 + 点登录 + 断言)===
hdc shell uitest uiInput click 300 400 # 聚焦账号框
Start-Sleep -Milliseconds 500
hdc shell uitest uiInput text user001 # 输入账号(获焦输入,API18+)
hdc shell uitest uiInput click 300 500 # 聚焦密码框
Start-Sleep -Milliseconds 500
hdc shell uitest uiInput text pass123 # 输入密码
hdc shell uitest uiInput keyEvent Enter # 回车提交(或点登录按钮)
# 断言:等待"登录成功"
hdc shell uitest dumpLayout -p /data/local/tmp/l.json
hdc file recv /data/local/tmp/l.json ./l.json
Select-String -Path l.json -Pattern "登录成功" # 命中即 PASS
# === 模板3:上滑浏览列表(带间隔,防丢步)===
for ($i=1; $i -le 5; $i++) {
hdc shell uitest uiInput dircFling 2
Start-Sleep -Milliseconds 800
}
# === 模板4:截图留证(带时间戳归档)===
$ts = Get-Date -Format "yyyyMMdd_HHmmss"
hdc shell uitest screenCap -p /data/local/tmp/shot_$ts.png
hdc file recv /data/local/tmp/shot_$ts.png ./reports/shot_$ts.png
# === 模板5:返回桌面 ===
hdc shell uitest uiInput keyEvent Home
# === 模板6:用例间清理(停应用 + 重新启动)===
hdc shell aa force-stop com.xxx.xxx
Start-Sleep -Seconds 1
hdc shell aa start -a EntryAbility -b com.xxx.xxx
十一、与前面笔记的闭环(完整自动化排障流)
1. hdc 连上(第1弹)
2. aa start 启动目标应用(本篇第八节)
3. uitest 做确定性 UI 流程(本篇):dumpLayout 查控件 → uiInput 精准操作 → 轮询等待 → 断言
4. 同时跑 hilog 盯异常(第3弹):
hdc shell hilog -L E | grep -iE "crash|freeze"
5. 压测用 wukong 补随机覆盖(第2弹):
hdc shell wukong exec -b com.xxx -a 0.3 -t 0.7 -T 30
6. 崩溃了查 faultlog(第5弹):
hdc file recv /data/log/faultlog/faultlogger ./faultlogs
7. 按键控制见第4弹(注意两套 keycode 体系)
十二、错误处理与重试
12.1 命令退出码
| 退出码 | 含义 | 处理 |
|---|---|---|
0 | 成功 | 继续 |
非 0 | 失败(命令未识别/参数错/设备断) | 检查命令大小写、参数、hdc 连接 |
PowerShell 判断上一步成败:
hdc shell uitest uiInput click 540 1150
if ($LASTEXITCODE -ne 0) {
Write-Host "点击失败,重试或截图"
hdc shell uitest screenCap -p /data/local/tmp/err.png
}
12.2 hdc 断连恢复
# 检测设备是否在线
if (-not (hdc list targets | Select-String "\d+\.\d+\.\d+\.\d+")) {
Write-Host "设备掉线,尝试重连"
hdc kill # 杀 hdc 服务
hdc start # 重启 hdc
Start-Sleep -Seconds 2
}
12.3 关键操作重试封装
function Invoke-UiClick {
param([int]$X, [int]$Y, [int]$Retry = 3)
for ($i=1; $i -le $Retry; $i++) {
hdc shell uitest uiInput click $X $Y
if ($LASTEXITCODE -eq 0) { return $true }
Start-Sleep -Milliseconds 500
}
return $false
}
十三、CI/CD 集成与多设备
13.1 多设备指定
hdc 默认操作第一台设备,多设备时必须用 -s <deviceId> 指定:
# 列所有设备 SN
hdc list targets
# 指定设备执行 uitest
hdc -s <deviceId> shell uitest uiInput click 540 1150
hdc -s <deviceId> shell uitest dumpLayout -p /data/local/tmp/l.json
hdc -s <deviceId> file recv /data/local/tmp/l.json ./device1_l.json
13.2 CI 流水线串接要点
| 环节 | 建议 |
|---|---|
| 环境准备 | CI 节点预装 hdc + uitest;流水线开始 hdc list targets 校验设备在线 |
| 用例隔离 | 每条用例前 aa force-stop 清理,用例间 sleep 1 |
| 报告归档 | 截图/控件树/日志按 用例名_时间戳 命名,统一存 reports/ |
| 失败处理 | 任何一步失败立即截图 + dump hilog,再标记用例 FAIL |
| 超时控制 | 每条用例设总超时(如 120s),避免卡死流水线 |
| 并发 | 多设备并行时,每个 job 绑定一个 -s <deviceId>,输出目录隔离 |
13.3 Jenkins/GitLab CI 最小示例
# run_ui_case.ps1 —— CI 调用入口
param([string]$DeviceId, [string]$CaseName)
$ErrorActionPreference = "Stop"
$ts = Get-Date -Format "yyyyMMdd_HHmmss"
$reportDir = "reports/$CaseName/$ts"
New-Item -ItemType Directory -Path $reportDir -Force | Out-Null
hdc -s $DeviceId shell aa force-stop com.xxx.xxx
hdc -s $DeviceId shell aa start -a EntryAbility -b com.xxx.xxx
Start-Sleep -Seconds 2
# ... 执行用例步骤 ...
# 收尾归档
hdc -s $DeviceId shell uitest screenCap -p /data/local/tmp/final.png
hdc -s $DeviceId file recv /data/local/tmp/final.png "$reportDir/final.png"
hdc -s $DeviceId shell hilog -x > "$reportDir/hilog.txt"
Write-Host "报告归档至 $reportDir"
十四、常见报错对照表
| 现象 | 可能原因 | 排查/解决 |
|---|---|---|
uitest: command not found | 系统未内置 uitest / PATH 缺失 | 确认设备为 HarmonyOS/OpenHarmony 全量版;部分精简版无 uitest |
子命令不识别(如 uiinput 报错) | 子命令大小写错 | 用骆驼峰 uiInput/dumpLayout/screenCap/uiRecord |
| 命令无任何响应/卡住 | testmode 未开 | param set persist.ace.testmode.enabled 1 后重试 |
dumpLayout 返回空 JSON | 无焦点窗口 / 应用未前台 | 先 aa start 拉起应用再 dump |
click 后界面无反应 | 坐标偏 / 控件不可点 | dumpLayout 读 bounds 取中心;确认 clickable:true |
inputText 没反应 | 控件未获焦 / 不可输入 | 先 click 聚焦;确认控件 type:TextInput |
text 命令报错 | API < 18 | 改用 inputText x y 文本 |
keyEvent 按键无效果 | 用错 keycode 体系 | 用名称(Home/Back);详见第4弹 |
screenCap 拉回文件 0 字节 | 路径无写权限 | 改用 /data/local/tmp/ 路径 |
file recv 报 not found | 设备上文件未生成 | 先确认 dumpLayout/screenCap 命令成功执行 |
| 回放脚本偏移 | 分辨率/时序差异 | 录制与回放需同分辨率;操作间加 sleep |
十五、新手必踩的坑 + 标准作业流(SOP)
15.1 必踩的 6 个坑
- 命令大小写错 → 主命令
uitest小写,子命令uiInput/dumpLayout/screenCap/uiRecord是骆驼峰。全小写写成uitest uiinput可能不识别。 - keyEvent 的 keycode 用错体系 →
uitest keyEvent用 ArkTS 枚举/名称(Home=1),不是input keyevent的底层数字(3)。优先用名称Home/Back/Power。 - 裸坐标点偏 → 屏幕坐标以像素计,且可能因分辨率/状态栏偏移。优先按 id/text 属性定位(5.3),其次
dumpLayout读bounds取中心,别裸猜。 - uitest 无响应 → 部分版本需先
param set persist.ace.testmode.enabled 1使能(见第二节)。 - 连续操作太快丢步 → 界面跳转有延迟,连续
uiInput之间必须 sleep 或轮询等待(第九节)。这是新手脚本"时灵时不灵"的头号原因。 - 只操作不验证 → 没有断言的脚本不是测试。至少在关键步骤后 dumpLayout grep 一下结果(第九节 9.2)。
记忆口诀:查控件用 dumpLayout,定位优先 id/text;操作之间要等待,结果必须做断言;keyEvent 用名称,无响应先开 testmode。
15.2 标准作业流(SOP)
1. hdc 连上,确认 uitest --version 可用(不行就开 testmode)
2. aa start 启动目标应用(第八节)
3. dumpLayout -p 导出控件树,recv 回 PC
4. 按 id/text 属性定位控件(jq/grep,5.3),算中心点坐标
5. uiInput click/doubleClick/longClick 点它
6. 要输入 → 先 click 聚焦,再 inputText/text
7. 要滑 → swipe/drag/dircFling
8. 每步后 sleep 或轮询等待目标控件出现(9.1)
9. 关键步骤后 dumpLayout 做断言(9.2)
10. screenCap 截图留证
11. 复杂流程 → uiRecord 录制,read 复盘,replay 回放
12. 异常 → hilog/faultlog 联动(见配套笔记)
13. 用例结束 → aa force-stop 清理
十六、一句话速记卡(贴显示器上)
uitest = 控件级 UI 自动化(比 wukong 精准,比 keyevent 完整)
前提: hdc 连上; 无响应先 param set persist.ace.testmode.enabled 1
选型: 临时验证用命令行; 长期回归套件写 ArkTS UiTest
命令(注意大小写!):
uitest uiInput click x y 单击
uitest uiInput doubleClick x y 双击
uitest uiInput longClick x y 长按
uitest uiInput swipe x1 y1 x2 y2 [速度] 滑动
uitest uiInput drag x1 y1 x2 y2 [速度] 拖拽
uitest uiInput dircFling 2 上滑(0左1右2上3下)
uitest uiInput inputText x y 文本 坐标输入
uitest uiInput text 文本 获焦输入(API18+)
uitest uiInput keyEvent Home 按键(用名称!非底层数)
uitest dumpLayout -p 文件 查控件树(bounds)
uitest screenCap -p 文件 截图
uitest uiRecord record 录制(Ctrl+C 结束)
uitest uiRecord replay 回放
定位: 优先 id > text > 坐标; jq 解析 bounds 取中心
等待: sleep 0.5~1s 或轮询 dumpLayout; 别写死长 sleep
断言: dumpLayout grep 控件文本/状态; hilog 抓异常做隐式断言
启动: aa start -a Ability -b 包名; 清理: aa force-stop
多指: 命令行不支持, 找 ArkTS UiTest
十七、安全注意事项
- 密码/敏感输入:避免明文进 shell history。用环境变量、
Read-Host -AsSecureString,或临时文件读取后立即删除。明文密码还可能被 hilog 记录,敏感字段建议测试账号专用。 - testmode 开关:
persist.ace.testmode.enabled 1会让控件树对所有调试工具可见。生产/外发设备测完务必关闭(param set ... 0)。 - 截图脱敏:归档截图前检查是否含账号、手机号等敏感信息,CI 报告建议存内部系统不外传。
- 录制动效:
uiRecord record会记录控件属性(含文本),录制含敏感信息的界面时注意保管 csv 文件。 - 设备权限:uitest 操作能力等同人工操作,可触发支付/删除等危险动作。自动化脚本需有操作白名单,避免误触不可逆操作。
参考来源
- 华为开发者文档:UI 测试框架使用指导(命令行测试能力)
- 华为设备开发文档:UITest 命令行指南
- ArkTS UiTest 框架:@ohos.uitest API 参考
- 实践参考:UI 测试框架使能命令
param set persist.ace.testmode.enabled 1(OpenHarmony 场景) - 配套系列:aa/bm 能力管理见「hdc 环境配置详解」· keycodeType 枚举见「keycodeType 详解与 hdc 发送按键」· ArkTS 图形化测试见「DevEco Studio 图形化测试」(同系列文章均在个人主页发布)
写在最后
本文是「鸿蒙系统测试笔记」系列的第 6 弹,聚焦命令行 uitest 的工程化实战。系列共 13 篇,覆盖 hdc 环境、wukong 压测、hilog 日志、keycodeType 按键、faultlog 崩溃分析、uitest 自动化、DevEco 图形化、SmartPerf 性能、DevEco Testing 专项、DFX 全家桶、分布式协同、安全合规、测试方法论等内容,欢迎到个人主页查看完整目录。
原创声明:本文为作者原创整理,基于鸿蒙官方文档结合实际测试实践编写。转载请注明出处,禁止删改摘要与原创声明后搬运。文中命令与脚本均在真实设备验证,但鸿蒙版本迭代较快,部分命令的 API 版本要求以设备实际为准。
如果觉得有帮助,欢迎点赞收藏;有问题欢迎评论区交流。
更多推荐



所有评论(0)