AI测试-03-Scenix项目实战复盘

第十四章前两篇如果只停留在“AI 测试值不值得做”和“Midscene.js 能解决什么问题”,很容易还是概念层内容。
真正能把这一章立住的,还是得回到一个具体仓库,拆它现在已经做到了什么、没做到什么、下一步该优先补什么。

这篇就只看一个项目:

Scenix。

这次复盘不是根据宣讲材料写,也不是根据一张架构图去反推,而是直接基于本地仓库 /tmp/scenix 的内容来判断,包括:

  • README.md
  • docs/design.md
  • docs/development-plan.md
  • client / server / core / tests 的工程结构

先说结论:

Scenix 现在已经跨过了“纯脚手架”阶段,最小可用链路基本成形,但还远不到成熟可用。

它和不少只停留在“AI 自动化愿景说明”的仓库不一样,已经能看到这些具体事实:

  • 前后端分层是明确的
  • SQLite 持久化已经落地
  • 测试套件执行链路已经串到 TestRunner
  • SSE 实时推送已经打通
  • Web、Android、iOS 三类 Agent 入口已经存在

但如果把标准提高到“团队可以长期依赖”的平台,Scenix 现在最明显的问题也已经暴露出来了:

  • 执行链路可以跑,但还不够稳
  • 报告结构已经有入口,但证据闭环不完整
  • 设备发现已经有了,但资源调度和占用治理还不成熟
  • 架构已经分层,但很多能力还停留在第一版

所以这篇文章不写产品介绍,而是只回答 6 个问题:

  • 为什么要做这个项目
  • 当前架构到底是什么
  • 最小可用链路已经闭合到什么程度
  • 现在最有价值的阶段成果是什么
  • 还不成熟的部分具体卡在哪里
  • 下一步最该优先补哪几块

一、为什么要做:不是为了把自然语言接到 UI 自动化上,而是为了把“自然语言测试”变成可管理的执行系统

README.md 和设计文档看,Scenix 的目标很明确:

  • 基于 Midscene.jsAppium
  • 用自然语言描述测试步骤
  • 覆盖 Web / Android / iOS
  • 以测试套件为执行入口
  • 用“套件总报告 + 子用例报告”组织结果

这个方向本身不新鲜。
真正有价值的部分不在“自然语言写步骤”,而在于它没有把项目停留在单机脚本层,而是继续往平台化方向推进了:

  • 有前端页面
  • 有后端 API
  • 有持久化
  • 有实时状态推送
  • 有测试套件模型

这说明项目真正想解决的问题不是“写一个 AI Agent 跑页面”,而是下面这件事:

把 AI 驱动的 UI 自动化能力,从单次脚本执行,收敛成一个可创建、可编排、可运行、可观察、可复看的系统。

这个判断很关键。

因为如果只是做 PoC,通常只需要:

  • 写一个示例脚本
  • 接一个模型
  • 跑一次页面操作
  • 输出一份报告

但 Scenix 明显不是停在这里。
它已经开始处理平台阶段才会遇到的问题:

  • 用例和套件如何建模
  • 执行状态如何实时同步
  • 报告目录如何统一
  • 数据如何跨重启保留
  • 移动端设备如何进入执行入口

这也是 Scenix 当前最值得肯定的一点:

方向上并没有把 AI UI 自动化理解成“多写几个 Prompt”,而是已经开始往工程化收口。

二、当前架构:不是一个单体脚本仓库,而是比较清晰的三层结构

从工程结构看,Scenix 已经形成了比较标准的三层拆分:

  • client:前端控制台,React + Vite + Ant Design
  • server:控制面和数据面,Express + SQLite + SSE
  • core:真正执行测试的核心层,负责解析步骤并分发到不同 Agent

这套拆法是合理的,因为 AI 测试平台最怕的一件事,就是把所有逻辑都堆在执行脚本里。
一旦这样做,后面这些能力会非常难补:

  • 用例管理
  • 套件编排
  • 状态同步
  • 执行记录
  • 结果归档

Scenix 当前的结构至少避免了这个问题。

1. 前端层负责控制台而不是执行逻辑

client/src/pages 下面已经能看到:

  • Dashboard.tsx
  • TestCases.tsx
  • TestSuites.tsx
  • TestRun.tsx
  • Reports.tsx
  • Devices.tsx

这说明控制台的页面模型已经基本拉出来了。
它不是只有一个演示页,而是把平台最核心的对象都分开了:

  • 用例
  • 套件
  • 执行
  • 报告
  • 设备

同时,useSSE.ts 说明前端已经不是纯轮询刷新,而是开始按事件驱动更新执行状态,这对测试平台很重要。
因为测试执行类系统如果没有实时反馈,使用体验会退化得很快。

2. 服务端层开始承担平台控制面的职责

server/src/routes 里已经有:

  • test-cases.ts
  • test-suites.ts
  • test-runs.ts
  • devices.ts
  • events.ts

这里最值得注意的是 test-runs.ts
它不是简单记录“用户触发了一次执行”,而是已经在做这些事:

  • 校验 suiteId
  • 校验平台和设备是否匹配
  • 创建 test_runs
  • 创建 test_run_items
  • 先返回 201
  • 再异步执行 executeSuiteRun
  • 状态变化后广播 test-run:updated

这说明 Scenix 已经开始从“执行命令式接口”走向“有状态执行对象”的平台模式。
这一步很重要,因为一旦执行对象没有状态机,后面就很难做:

  • 列表展示
  • 实时进度
  • 错误归因
  • 结果回看

3. 核心执行层保持了平台无关性

core/src/runner/test-runner.ts 的职责比较清楚:

  • 解析自然语言步骤
  • 按平台分发到 web / android / ios
  • 按步骤调用 aiAction()aiAssert()
  • 统一返回 TestResult

从架构角度看,这是当前仓库里最像“核心抽象”的一层。
它没有把前端和数据库逻辑卷进去,也没有把路由层耦死到具体平台执行代码里。

这层虽然还比较轻,但方向是对的。

三、最小可用链路:现在已经能闭合,但还只是第一版闭合

判断一个 AI 测试平台是不是已经跨过脚手架阶段,最直接的方式不是看页面多不多,而是看有没有一条真实可用链路。

Scenix 现在已经具备下面这条最小可用链路:

  1. 创建测试用例
  2. 把一个或多个同平台用例编进测试套件
  3. 从测试套件发起执行
  4. 根据平台选择是否要求设备
  5. 服务端持久化执行记录和子项记录
  6. TestRunner 真正执行
  7. 前端通过 SSE 实时看到状态变化
  8. 执行结果写回列表和报告入口

这条链路为什么重要?

因为它说明项目已经不只是“能跑一个 AI 步骤演示”,而是已经把下面几种对象连起来了:

  • 测试定义对象
  • 套件对象
  • 执行对象
  • 设备对象
  • 状态对象

最小可用链路的实际骨架

如果按工程视角去拆,Scenix 当前的最小链路大概是这样:

第一段:定义层

  • test_cases 表持久化测试用例
  • test_suites + test_suite_cases 建立套件和用例关系

第二段:触发层

  • POST /api/test-runs
  • 根据 suiteId 查套件
  • 根据平台决定是否要求 deviceId

第三段:执行层

  • 服务端把状态从 pending 改成 running
  • executeSuiteRun() 顺序执行同一套件里的各个用例
  • TestRunner 再按平台分发给 Web / Android / iOS Agent

第四段:反馈层

  • event-bus.ts 广播 test-run:createdtest-run:updated
  • 前端 useSSE 订阅后刷新列表和详情

第五段:结果层

  • 执行记录持久化进 test_runstest_run_items
  • 报告目录统一挂到 /reports/midscene_run

这已经是一条完整链路了。
但要注意,它现在还是:

第一版闭合,不是成熟闭合。

它能用来证明“这个平台方向是能跑起来的”,但还不足以证明“这个平台已经适合团队长期依赖”。

四、关键模块拆分:当前最有价值的不是功能多少,而是边界已经初步成形

从项目当前状态看,最值得保留的不是某个页面,而是这几个模块边界已经比较清楚。

1. 用例模块和套件模块分开了

Scenix 明确区分了:

  • 单条自然语言测试用例
  • 套件级执行入口

这比“直接执行单条 case”更适合平台化。
因为一旦执行入口直接绑到单 case,后面套件编排、顺序控制、汇总报告都会变得很别扭。

现在的建模至少做对了两件事:

  • 用例是原子定义单元
  • 套件是运行组织单元

同时 test-suites.ts 里还有一个重要校验:

  • 同一套件里的用例必须属于同一平台

这说明项目已经开始在模型层控制边界,而不是等执行时再碰运气。

2. 执行记录和执行子项分开了

数据库层有:

  • test_runs
  • test_run_items

这个设计很关键,因为套件执行天然就是“一个总记录 + 多个子执行项”的关系。
如果没有 test_run_items,后面会很难处理:

  • 套件内单条 case 的状态差异
  • 多条 case 的错误定位
  • 总状态与子状态的映射

虽然这套模型现在还不算丰富,但方向没有问题。

3. 设备发现和执行设备选择分开了

server/src/services/device-service.ts 当前做的是“发现设备”,包括:

  • Android 通过 adb devices -l
  • iOS 在 darwin 下通过 xcrun xctrace list devicesidevice_id -l

同时 iOS 设备还会结合 IOS_WDA_HOSTIOS_WDA_PORTS 生成带 wdaPort 的设备项。

这说明 Scenix 已经意识到移动端执行不是只拿一个 udid 就够,至少还得考虑:

  • 平台差异
  • WDA 连接配置
  • 设备列表刷新

虽然还没有走到资源治理那一步,但设备对象已经进入平台模型了。

4. SSE 事件总线和页面订阅是成对出现的

有些平台类项目会只做后端广播,不做前端重连和页面消费;也有些会只做前端刷新,不做真正事件流。
Scenix 现在是两边都落了:

  • 后端有 event-bus.ts
  • 前端有 useSSE.ts

而且设计文档里明确写了:

  • 事件类型
  • 心跳
  • 指数退避重连

这意味着“执行是异步过程”这件事已经被认真对待,而不是只写了一个演示级接口。

五、阶段成果:哪些地方已经明显不是 PoC 水平

如果把标准定成“是否已经从演示项目进入第一版可用项目”,Scenix 当前至少有 5 个阶段成果是明确的。

1. 数据已经不再是内存态

docs/development-plan.md 把项目早期痛点写得很清楚:

  • 早期版本是内存数组存储
  • 服务重启会丢数据
  • 执行只是模拟

而现在 server/src/db/index.ts 已经做了这些事:

  • SQLite 初始化
  • 自动建表
  • WAL 模式
  • 索引创建
  • snake_case -> camelCase 映射

这说明 Scenix 至少已经从“演示态”跨到了“可保留对象”的阶段。

2. 执行已经从模拟跑法切到了真实 Runner

开发计划里把“对接 TestRunner”单独列成 Phase 2,当前代码里也能看到 test-runs.ts 已经直接引用了:

  • TestRunner
  • type TestCaseInput

这比“点击执行后 sleep 3 秒再改状态”成熟很多。
因为它说明平台最关键的价值链路已经开始和真实执行对接,而不是继续留在假执行状态。

3. 状态同步已经不是手动刷新

执行系统如果只能手动刷新,基本还属于半成品。
Scenix 现在的 SSE 链路虽然不复杂,但足够说明项目已经认真处理“状态流”了。

这件事的价值不只是体验更好,而是它让这些对象开始具备真正的平台属性:

  • 正在运行
  • 已经失败
  • 已经完成
  • 被删除

这些变化不是页面上临时算出来的,而是有事件驱动。

4. 跨平台边界已经显式写进执行模型

README.md 明确写了:

  • Web 套件不需要设备
  • Android 套件需要 Android 设备
  • iOS 套件需要 iOS 设备和 WDA 配置

test-runs.ts 里也有对应校验逻辑。
这说明 Scenix 没有试图把三端执行强行揉成一个“统一设备模型”,而是接受了多平台差异本来就存在。

这是对的。
AI 测试平台如果一开始就想把所有平台差异抹平,后面往往会在真实执行里出问题。

5. Monorepo 结构让后续扩展空间是存在的

pnpm workspace + client/server/core 这种结构虽然不新鲜,但对这类项目是合适的。
因为后面真要继续做:

  • 模型配置治理
  • 报告详情页
  • 并行执行
  • 定时执行
  • 权限控制

都需要前端、服务端、执行层分别演进。
现在这三层至少已经拆出来了。

六、还不成熟的部分:当前最明显的缺口有 6 个

Scenix 最大的问题不是“有没有想法”,而是:

已经跨进了平台阶段,所以它的短板也开始从脚本问题变成平台问题。

1. 报告入口存在,但证据闭环还不完整

仓库里已经有:

  • Reports.tsx
  • /reports 静态目录
  • reportPath

这说明项目知道报告是核心结果对象。
但从当前 TestRunner 返回值看,reportPath 并不是稳定落地的强约束,执行结果更多还是状态和错误信息级别。

这会带来一个直接问题:

  • 能知道失败了
  • 但不一定能完整复盘失败现场

AI UI 自动化项目最怕这种状态。
因为这类问题天然比传统脚本更需要证据链,至少要能稳定对应到:

  • 原始步骤
  • 模型动作
  • 关键截图
  • 执行日志
  • 报告入口

当前仓库已经有报告目录概念,但还看不到足够成熟的证据分层。

2. 套件执行是顺序链路,但还不是成熟调度链路

executeSuiteRun() 现在是直接在服务进程里顺序跑。
这对第一版是可以接受的,因为实现简单,也容易把链路先跑通。

但它的边界也很明显:

  • 没有真正的任务队列
  • 没有并发治理
  • 没有租约
  • 没有执行隔离
  • 没有 worker 层的状态回传协议

只要执行量稍微上去,下面这些问题就会出现:

  • 一条长任务拖住整个服务进程
  • 多设备、多套件时资源互相抢占
  • 服务重启时运行中状态难以收敛
  • 失败任务的补跑和恢复不好做

这说明 Scenix 现在更准确的状态是:

已经有执行模型,但还没有成熟调度模型。

3. 设备能发现,但设备资源还没有真正被治理

当前 device-service.ts 解决的是“发现什么设备在线”,但没有真正解决这些问题:

  • 设备是否被哪个任务占用
  • 设备是否处于脏状态
  • 设备是否能安全复用
  • 设备失败后该怎么恢复
  • iOS 多端口映射是否会冲突

也就是说,现在的设备对象更像“可选项”,还不是“被治理的资源”。
对移动端 AI 自动化来说,这个缺口会很早暴露。

4. AI 配置已经集中,但执行质量治理还没有深入展开

开发计划里把 AI 配置模块 列得很清楚,也说明支持:

  • OpenAI
  • Qwen
  • Anthropic

这说明模型配置集中管理已经开始做了。
但当前仓库里还看不到足够成熟的这些能力:

  • 不同模型的行为差异治理
  • Prompt/指令模板版本治理
  • 失败重试和重规划的可观测性
  • 幻觉动作与误断言的归因分层

当前 TestRunner 只是按步骤调用 aiAction() / aiAssert(),失败时统一报“最多已尝试 3 次重规划”。
这对于第一版能跑是够的,但对于平台排障远远不够。

5. 执行状态有了,但业务决策状态还没有形成

当前状态机主要是:

  • pending
  • running
  • passed
  • failed
  • error

这对执行系统是够用的。
但如果平台继续往前走,后面一定会遇到更细的决策问题:

  • 是否允许忽略
  • 是否允许重跑
  • 是否属于环境问题
  • 是否属于脚本问题
  • 是否属于模型误判

如果没有这层更细的决策模型,平台最终仍然会退化成“看一个总状态颜色”的系统。

6. 当前仓库更像单实例系统,还没有走到多用户长期使用阶段

SQLite、单服务进程、SSE、本地设备发现,这些组合在第一版是合理的。
但也意味着当前架构更适合:

  • 小规模使用
  • 本地或单机部署
  • 快速验证方向

它还不适合直接外推成:

  • 大规模多人共用
  • 多实例执行
  • 长期排队调度
  • 多角色协作

这不是缺点,而是阶段事实。
但复盘时必须写清楚,不然很容易把“第一版可用”误写成“平台已经成熟”。

七、最该先补什么:优先顺序不是功能越多越好,而是把执行闭环补稳

如果现在继续往前做,最容易犯的错就是继续加页面、加概念、加模型支持。
但 Scenix 当前最缺的不是广度,而是稳定闭环。

更合适的优先顺序是下面这 5 件事。

1. 先补“执行证据包”

每次执行至少要稳定留下:

  • 套件级元数据
  • 子用例级步骤记录
  • 关键截图或页面快照
  • 模型动作和断言日志
  • 错误归因字段
  • 报告入口映射

没有这层证据包,后面排障会非常痛苦。

2. 再补“设备与执行资源治理”

移动端执行要尽快补的不是新页面,而是:

  • 占用状态
  • 租约
  • 执行前探活
  • 执行后回收
  • 脏设备恢复
  • 失败后隔离

否则平台一旦多人使用,最先崩的往往不是模型,而是设备环境。

3. 把“顺序执行”升级成“受控调度”

第二阶段不一定非要上复杂分布式系统,但至少要开始拆出:

  • 调度入口
  • 执行 worker
  • 任务状态回传
  • 超时和中断治理

只有这样,平台才能逐步支持:

  • 排队
  • 并行
  • 补跑
  • 自动恢复

4. 把 AI 失败分层写进结果模型

当前失败状态还比较粗。
后面至少要把这几类失败区分开:

  • 环境失败
  • 设备失败
  • 模型理解失败
  • 页面元素不可操作
  • 断言失败
  • 配置失败

只有把失败分层写进模型,报告和治理才会开始真正有价值。

5. 最后再考虑更大的平台能力

例如:

  • 定时执行
  • 标签和分组
  • 权限
  • PostgreSQL 迁移
  • 覆盖率

这些都可以做,但不该排在最前面。
因为在 Scenix 当前阶段,真正的瓶颈不是“功能不够多”,而是“执行和证据还不够稳”。

八、常见坑:这类 AI 测试平台最容易在 4 个地方看起来能用,实际不好用

1. 能执行,不等于可复盘

只要测试开始真的跑起来,就很容易把平台判断成已经成形。
但如果失败后不能快速回答下面这些问题,平台还是会卡住:

  • 哪一步失败了
  • 当时页面是什么状态
  • 是模型理解错了,还是页面没准备好
  • 是设备问题,还是环境问题

2. 有设备列表,不等于设备资源可用

设备能发现出来,只说明“看见了”。
它不说明:

  • 当前设备是否空闲
  • 当前端口是否可用
  • 当前 WDA 是否可通
  • 当前系统状态是否干净

3. 有实时状态,不等于执行链路稳定

SSE 做好之后,平台会显得“更像平台”。
但这解决的是观察问题,不是执行稳定性问题。

如果没有调度、重试、回收、证据包,实时状态只能让问题看起来更明显,不能让问题更容易解决。

4. 有三端 Agent,不等于跨平台能力已经成熟

Web、Android、iOS 的 Agent 入口都有了,这是好事。
但真正困难的是:

  • 三端失败模式不一样
  • 三端环境准备不一样
  • 三端证据采集不一样
  • 三端恢复动作也不一样

这部分如果没有继续往平台能力里收,三端支持很容易停留在“入口存在”。

九、真实案例型段落:一条套件已经发起,但页面上长时间停在运行中,最后并不是模型没返回

场景

一条 Android 测试套件已经在控制台创建完成,设备列表里也能看到目标真机。
点击执行后,前端 TestRun 页面出现了新记录,状态从 pending 变成了 running,但长时间没有进入最终状态。

执行

先从最短路径检查:

  • 前端是否收到 test-run:created
  • 前端是否收到后续 test-run:updated
  • test_runstest_run_items 是否已经写入
  • 服务端是否真的进入了 executeSuiteRun()
  • 设备选择是否和套件平台一致

现象

检查下来会发现:

  • 执行记录已经插入数据库
  • test-run:created 已经广播
  • 总状态已改成 running
  • 但子项迟迟没有稳定推进到 passed / failed / error

这时候很容易先怀疑模型调用慢,或者 Midscene 卡住。

排查

如果只盯模型层,很容易走偏。
更有效的顺序应该是:

  1. 先确认是不是 Web / Android / iOS 平台选择错误
  2. 再确认 device-service.ts 返回的设备对象是否真能用于执行
  3. 再看 TestRunner 是否已经拿到正确的 deviceUdid / deviceConfig
  4. 最后才回到 Agent 执行和模型响应

在这类链路里,最容易漏掉的是:

  • 设备列表能显示,不等于设备当前真可执行
  • iOS 的 wdaHost / wdaPort 组合能生成,不等于链路真打通
  • 总状态进入 running,不等于子项执行已经稳定开始

修复

更稳的修复方式不是只补一个超时,而是补三件事:

  • 执行前加入设备探活和可执行校验
  • 子项开始执行前记录更明确的阶段日志
  • 把“设备可见但不可执行”单独归类成设备层错误,而不是混进模型失败

这类问题很典型。
从页面看像“AI 执行慢”,从执行链路看其实更像“平台还缺少设备层的前置校验和错误分层”。

十、这篇复盘的最终判断

Scenix 当前最准确的阶段判断不是:

  • 一个成熟可用的 AI 测试平台

也不是:

  • 一个只会画架构图的概念仓库

而是:

一个已经把最小可用链路跑通、并且明显开始进入平台工程阶段的第一版项目。

它现在已经有几件事是明确成立的:

  • 有对象模型
  • 有前后端分层
  • 有真实执行入口
  • 有持久化
  • 有实时状态推送
  • 有跨平台执行边界

但同样也要明确写清楚:

  • 报告证据闭环还不成熟
  • 调度和资源治理还不成熟
  • 设备治理还不成熟
  • AI 执行失败分层还不成熟
  • 长期多人协作使用能力还不成熟

如果下一步继续推进,最值得先做的不是继续扩功能面,而是把下面这条链路补稳:

套件定义 -> 设备校验 -> 受控执行 -> 结构化证据 -> 失败分层 -> 可复盘报告

只要这条链路补稳,Scenix 才会从“已经能跑起来的 AI 测试平台第一版”,真正往“可长期使用的测试平台”继续走。