先从一次日常说起
去年我还在老老实实手写每一行 ArkTS。今年不一样了——我和朋友都开始把"让 AI 写页面、写业务逻辑"当日常。需求丢给 Agent,它吭哧吭哧写完,我 review 一眼,build 过,丢到真机上看一眼,就算通过了。
直到某天我意识到一个荒诞的事实:
我在用 AI 写代码,然后用最原始的方式测它写的代码——肉眼。
不是不行,是错位。Agent 一小时能产出别人一天的量,但"验证"这件事还停留在我点来点去的阶段。于是我想了一个我很怂的问题:
能不能让 AI 写完之后,自己测自己?
不是让 Agent 读代码然后说"我觉得没问题"(那等于没测),而是让它在真机上真的点、真的滑、真的断言,最后给我一个"通过/失败"的硬结论。
为什么不想自己写测试
你可能在想:写个 UI 自动化测试不就行了?Hypium 是官方框架,很强大。
是的,它强大,但它重——要建测试工程、要装测试框架、要写用例、要维护。这不是"写完代码顺手测一下"的东西,这是正经八百的测试项目。对个人开发者来说,为每个小迭代维护一套 Hypium 工程,投入产出比太虐了。
更关键的是:我给 Agent 用了 prompt 让它去写测试用例,得到的是灾难。 Agent 写的测试和我让它写的功能代码一样多产,但它没法替我做决定——用例该覆盖什么、界面上哪些是可变的、什么时候该等不该等。它写出来的用例,flaky 到我都不信它。最后人类还是卷进了"调试 Agent 写的测试"这个无底洞。
我算了笔账:让 Agent 写测试 → 人调试测试 → 这个环节消耗的时间,抵得上手写测试了。闭环没成立。
真正的解法:让「测试」成为 Agent 交付的一部分
后来我想通了。与其让 Agent 写一堆测试用例,不如直接把"测试动作"变得极轻,让验证内嵌进 Agent 的工作流里:
Agent 写好界面 → 在真机上跑几步真实交互 → 拿到硬判定的通过/失败 → 交付
这需要三件事:
- 一个操作 = 一条命令。 点一下控件就是
autoharmony ui click-by-text "登录",不再是几十行测试代码。 - 每次操作有确定性结论。 不是 AI 觉得通过,而是控件树级的硬判断:路由变了没、文字出现没、弹窗卡住没、进程崩了没。每个操作输出一行机器可读的 verdict,和一个 0/1 的退出码。
- 探索能沉淀成脚本。 Agent 在界面上点过的每一步都被录下来,存成 JSON。下次代码一改,
autoharmony script run一行重跑整套流程。
第三条是整件事的灵魂。Agent 探索一次,脚本复用 forever。 我把它做成了一个小工具链,开源了,叫 autoHarmony:
- 纯本地,毫秒级,不依赖任何大模型推理——每次判定都是确定性的,同一输入永远同一结论,不 flaky
- 每个操作自动拍控件树 before/after,route 跳转、弹窗、文字切换一目了然
- 闪退检测内建:CppCrash / JSCrash / AppFreeze 自动抓
- 一个 JSON 脚本跑全流程,单连接,CI 里直接 exit code 判断
一个真实的 3 分钟闭环
假设 Agent 刚给我写完登录页。它想验证"登录后应该进主页"这条路径:
# ① 探索:点一下"登录",断言路由跳到 MainPage
$ autoharmony ui click-by-text "登录" --expect-route "MainPage" --json
{"status": "SUCCESS", "reason": "route changed to MainPage", "exit": 0}
# ② 把整段探索录成回归脚本
$ autoharmony script record start
$ autoharmony ui click-by-text "登录"
$ autoharmony ui input-by-text "手机号" "13800138000"
$ autoharmony ui input-by-text "密码" "********"
$ autoharmony ui click-by-text "确认"
$ autoharmony script record stop --output login_flow.json
# ③ 两小时后我改了登录逻辑,Agent 直接重跑
$ autoharmony script run login_flow.json
{"all_passed": true, "steps": 5, "failed": 0}
感受一下这中间的差别。传统流程是:改代码 → 手动点一遍 → 祈祷没漏。现在是:改代码 → 一行命令 → 硬结论。Agent 交付的不再是"我写完了",而是"我写完了,并且我在真机上自己验证过了"。
(哦对,它的 --json 是给后面的掌控者的:Claude、GPT、任何 agent 都能直接解析 verdict,不用抠字符串。)
几个你可能没想到要、但绝对想要的功能
上面那条登录闭环跑通不难,难的是真机环境里防翻车的那几件破事——这些我全做进工具里了:
① 闪退检测,自动的。
Agent 每点一步,工具都会做进程存活检查 + faultlog 监控。CppCrash、JSCrash、AppFreeze 一旦发生,verdict 直接返回 CRASHED,附带崩溃详情,而不是让 Agent 对着一个莫名消失的界面发愣。
② 挡路的弹窗,命令行自带解除。
权限弹窗、升级气泡、活动横幅——全是自动化回归的杀手。工具自带 dismiss-dialogs 命令(--auto-handle-dialog 参数),能识别已知弹窗并点掉"确定/知道了",自动把挡路的杂物清掉再继续,Agent 只需要调一句,不用写死一个"点这里关弹窗"的脆弱用例。
③ 不知道控件在哪?让它自己滚。
App 里总有列表长到测试脚本够不着。ui scroll-find "关于我们" 会自动往下滚,滚到目标出现为止。对 Agent 来说,就是一行命令的事。
④ 界面验证之外,还能戳业务逻辑。 UI 操作只能验证"表面"。有些东西藏在界面后面——登录后的会话状态、设备在线情况、某条数据到底落没落库。界面上点对了,不代表背后状态就是对。
所以 autoharmony 内置了一个 JSON-RPC 的 TCP bridge,Agent 可以直接调用 App 侧注册的业务方法——登录登出、用户信息、业务数据,App 暴露什么就能调什么,把"看到的"和"实际的"对上:
from bridge.tcp_bridge import TcpBridge
bridge = TcpBridge("your-device-id")
# 登录 / 登出、用户信息、业务数据,都是 JSON-RPC 一行调用
bridge.call("login", {"account": "13800138000"})
info = bridge.call("getUserInfo") # → {"nickname": "星河", "vip": true}
devices = bridge.call("queryDevices", {"room": "客厅"}) # → {"devices": [...]}
bridge.call("logout")
bridge.close()
界面点过去的是一个"登录成功页",但会话、用户态、底层数据到底对不对,这一行就查清楚了。
Agent 不再只能看界面"表演",它能直接戳 App 底层去抽查状态。对 Agent 来说,这是多了一双伸进代码里的手:UI 断言负责"长什么样",Bridge 负责"实际是什么"。双保险,翻车率再降一截。
为什么我刻意不选"AI 视觉"路线
现在市面上流行一类 AI 测试工具:让多模态大模型看截图,用自然语言指挥它"点这个、拖那个"。很酷,对,很多场景是刚需——当你要验证"界面长得对不对"时,视觉方案无可替代。
但极端相反:当你要跑回归时,视觉方案恰恰是最糟糕的选择。
回归测试的本质是"确定性":
- 100 次同样的运行,必须给出 100 次同样的判定。而大模型是概率性的——同样的截图,改个 prompt 温度、升级个模型,结论能不一样。
- 每次操作几秒的推理延迟,对一条几十步的回归流程,成本感人。
- 你在 code review 时没法审计"大模型当时为什么觉得这步通过了"。
所以我的取舍是:
- "看"交给视觉模型——检查颜色、布局、视觉还原,它擅长;
- "判断"交给确定性引擎——回归、断言、diff,同一输入永远同一输出,毫秒级,可审计。
autoharmony 是后者:不给 Agent 一双会看图的眼睛,而给它一把能反复落下的令旗。它快、稳、可复现,而且——是唯一一条为 HarmonyOS 而生的路。
它对我是工作方式,对你可能也是
做的过程中我最大的体会:所谓"给 Agent 配套测试",不是一个工程问题,是一个信任问题。你什么时候敢把代码交给你自己写的 AI?不是当它说"我测过了"的时候,而是当它能向你证明它测过的时候。
验证越便宜,信任越便宜。把验证做到一行命令,Agent 可信度就上了一个台阶。我现在不太担心 AI 写的代码翻车了,因为验收是自动的、强制的、可量化的。
如果你也在一行行跟 Agent 交付的代码搏斗,欢迎来玩:
- 仓库:github.com/qkdndqxkr5-…
- 一行上手:
pip install autoharmony && hdc list targets - 中文文档在 README 里
如果它对你有用,点个 ⭐ —— 让更多正在为"AI 写完没人测"头疼的鸿蒙开发者看到它。