feat(tester): add integration-first journey execution

This commit is contained in:
2026-10-15 18:11:28 +08:00
parent c2eb207bd2
commit 3a18a27dc6
13 changed files with 662 additions and 29 deletions
+2
View File
@@ -41,6 +41,8 @@ catalog(整个测试集)
| `expected` | 怎么算过:`{kind, value}` 列表 | pytest `assert`;Robot `Should …` | 不是步骤 |
| `run_together` | 必须成组执行的用例(有序、可选 continue_on_fail) | 场景组(scenario) | 不是 suite,不是 tag |
| `client_suite` | 客户端用户旅程套件:`client-smoke` / `client-regression` / `safety` | mobile/browser E2E suite | 不是 `category`,也不是通用 tag;迁移期可读 `suite` 别名 |
| `test_type` | 顶层测试类型:`journey` 或 `integration` | E2E vs service/contract test | 不是 driver;旧目录可由既有字段推断 |
| `integration_suite` | 集成套件:`api-contract` / `authorization` / `build-contract` | API/contract test suite | 不是客户端 `client_suite`;迁移期可读 `suite` 别名 |
| `journey` | 用户目标、入口、操作、UI 断言、最终状态和失败继续策略 | Cucumber scenario / Robot task | 不是 API contract |
| `fixture` | 旅程开始前声明的测试账号与隔离数据 | pytest fixture | 不是运行中临时猜出的数据 |
| `cleanup` | 本轮数据的 teardown 契约;缺失会在 preflight 阻断 | pytest teardown / Robot teardown | 不是测试通过后的可选备注 |
+31 -5
View File
@@ -9,6 +9,11 @@ Agent、执行目标和临时 terminal 的完整协议见 [execution.md](executi
## 0. 建立测试矩阵并完成全量 preflight
`test-preflight` 是 integration 和 journey 的共同硬闸。tester 必须先调用其 `verify`
或 `prepare`,保存独立的 preflight YAML/CSV;状态为 `blocked` 或 `environment-fail`
时不创建 browser/mobile session,所有尚未执行的 testcase 记 `not-run`。preflight 证据
不算 testcase,也不进入 testcase CSV/YAML 的总数。
测试不是“找到一个能跑的设备就开始”。每轮先建立一份测试矩阵;移动端每个目标产物
必须单独占一行:
@@ -76,6 +81,7 @@ python3 <skill-dir>/scripts/catalog.py select --root <root> \
[--category CAT] [--id ID]... [--tag smoke|full|slow] \
[--max-risk <risk>] [--driver script|browser|mobile] \
[--automation automated|assisted|manual|any] \
[--test-type integration|journey] [--suite <client-or-integration-suite>] \
[--platform android|ios]... \
[--artifact android=<path-or-url>] [--artifact ios=<path-or-url>] \
[--binding android=tester.android] [--binding ios=tester.ios]
@@ -90,6 +96,15 @@ python3 <skill-dir>/scripts/catalog.py select --root <root> --suite client-smoke
`client-smoke`、`client-regression`、`safety` 是 `client_suite` 的固定值,不替换既有
`tag=smoke|full|slow`。`safety` 不参与未指定范围的默认选择。
集成测试显式选择:
```bash
python3 <skill-dir>/scripts/catalog.py select --root <root> --test-type integration
python3 <skill-dir>/scripts/catalog.py select --root <root> --suite api-contract
```
未指定 `--test-type`/`--suite` 时,默认选择不会包含 `test_type=integration`。
选中任一 `driver=mobile` 用例时,`--platform`、每个平台的 `--artifact` 和对应
`tester` binding 是硬性参数;`catalog.py select` 会检查产物文件/下载地址和
`.pouch/agent.yaml` 中的 binding。缺任何一项直接返回非零并打印 `preflight: blocked`,
@@ -106,7 +121,18 @@ python3 <skill-dir>/scripts/catalog.py select --root <root> --suite client-smoke
无命中:停下说明筛选条件,不要扩大范围。
## 2. 运行前闸
## 2. 双层执行
preflight 通过后,先按 catalog 顺序执行 `integration`,再按客户端套件顺序执行
`journey`。集成服务不可达是 `environment-fail`;服务已达但 API/权限/数据契约断言错误
是 `fail`。任何 integration `fail` 都阻断依赖的 journey,并把它们记为 `not-run`;此时
不得创建客户端 session。正确测试账号登录失败发生在客户端已启动后,仍是产品 `fail`。
运行器可复用 `scripts/two_tier.py` 的 `run_integration_first`,它只接收外部 driver
回调,不实现 API、浏览器或移动执行器;mock fixture 只能验证调用顺序和失败传播,不能
冒充真实部署、Mac 或设备成功。
## 3. 运行前闸
- `HOST` 未设(环境变量 / `local.yaml` 都没有):全部停,environment-fail。
- 命中条的 `risk` 在 catalog `authorize` 里有对应变量:变量不是 `true` 则该条 `skipped`。有 `gate` 时还要 `catalog.gates` 对应变量为 `true`;`assume` 不成立同样 `skipped`。即使用户点了 id 也不执行。
@@ -123,7 +149,7 @@ python3 <skill-dir>/scripts/catalog.py select --root <root> --suite client-smoke
- 探测不可达或命中 `stop_if`:在 preflight 阶段记录对应分类/平台的不可用项并停止整轮;
先返回用户处理,不创建后续测试 session。只有所有本轮目标环境通过,才进入用例执行。
## 2.1 移动端平台环境闸门与用户引导
## 3.1 移动端平台环境闸门与用户引导
`driver=mobile` 不是一个可以互换的平台。运行前必须根据 catalog session、用例变量或用户指定,明确本轮是 Android 还是 iOS;无法判断时先停下询问平台,不得猜测。两类平台分别执行以下闸门:
@@ -184,7 +210,7 @@ Android+iOS 默认是全量 preflight 闸门:任一项不满足,另一平台
环境引导只负责让用户补齐前置条件;除 catalog 已明确授权的 session 初始化外,不自动安装 SDK、配对真机、修改系统安全设置或上传产物。
## 3. Session
## 4. Session
看命中条用到的 `session` 键:
@@ -193,7 +219,7 @@ Android+iOS 默认是全量 preflight 闸门:任一项不满足,另一平台
- `reuse: run`:整轮结束再关。`persist`:不关。
- 中途 session 挂了:后续同 driver 标 environment-fail,不要标产品失败。
## 4. 执行
## 5. 执行
按 select 返回的顺序,一条一条来。select 按 `catalog.yaml` 的 `categories` 顺序,同一分类内按该 yaml 列表顺序(不是文件名字母序)。默认失败即停(产品 `fail` 或探测到的不安全状态)。用户说继续 / keep-going 才往后跑。
@@ -225,7 +251,7 @@ python3 <skill-dir>/scripts/catalog.py run-script --root <root> --id <id>
挂到已有 session,执行 `how.steps`,对照 `expected`。必须留下可见文本、URL 或交互证据。
## 5. 记录与报告
## 6. 记录与报告
每条:`id, result, evidence, notes`。`result` 只能是 `pass` / `fail` / `environment-fail` / `skipped` / `not-run`。`skipped` 是主动不跑(retired / pending / 超风险上限 / 未授权 / `assume` 不成立),`not-run` 是没轮到(失败即停后剩下的 / 被前置整组挡住的 / 需人工而无人值守的)。
+17 -4
View File
@@ -14,10 +14,9 @@ runs/<run-id>.yaml 每次运行快照(执行源);run-id 必须唯一
runs/*.csv 同一次运行的成绩单;generate_run_csv.py 从对应 yaml 生成
```
客户端旅程在上述目录中仍使用同一套 cases/runs 和五态报告,不另造成绩单。启用旅程
契约的用例声明 `client_suite`(兼容迁移期别名 `suite`);catalog 可用
`client_suites` 显式列出三个标准套件:`client-smoke`、`client-regression`、`safety`。
`category` 仍是文件/执行顺序容器,不被套件字段替代。
两类用例共用同一套 cases/runs 和五态报告,不另造成绩单。新目录显式声明顶层
`test_type: journey | integration`;旧目录没有该字段时按已有 `client_suite`/`journey`
或 `integration_suite` 推断。`category` 仍是文件/执行顺序容器,不被套件字段替代。
## catalog.yaml
@@ -35,6 +34,7 @@ runs/*.csv 同一次运行的成绩单;generate_run_csv.py 从对
| `run_together` | 可选。成组执行:`[{ids: [TC-…, TC-…], continue_on_fail: true}]`。点到组内任一条,`select` 会按 `ids` 顺序把整组扩进命中列表。`continue_on_fail: true` 时组内前一条产品 fail 仍跑后一条(返回/收尾)。一个 id 只能属于一组。 |
| `status_probe` | 可选。顶层默认值,一个**分类级前置条件**:`{url, stop_if: {字段: [命中值]}}`。运行前请求 `url`,响应命中任一 `stop_if` 条件即视为前置不满足。分类项可用同名键覆盖:缺省继承顶层、`false` 关闭、mapping 整体替换。命中或不可达只影响用它的分类,不是产品失败。业界对应 pytest 的 session fixture / Robot 的 Suite Setup。`select` 会按分类返回解析后的生效值,`url` 已用 `vars` 展开 |
| `client_suites` | 可选的标准套件声明;出现时必须完整包含 `client-smoke`、`client-regression`、`safety`。缺省运行仍按 `tag` 兼容旧目录 |
| `integration_suites` | 可选的集成套件声明;标准值为 `api-contract`、`authorization`、`build-contract` |
`local.yaml` 与环境变量覆盖 `HOST` 和授权开关。模板中的 `HOST` 默认是
`127.0.0.1`;远程目标必须显式覆盖。查找顺序:环境变量 > `local.yaml` >
@@ -76,6 +76,7 @@ terminal;运行结束用 `orca terminal close --terminal <handle>` 关闭本
| 字段 | 必填 | 含义 |
|------|------|------|
| `id` | 是 | 匹配 `id_pattern` |
| `test_type` | 新用例是 | `journey` 或 `integration`;缺省兼容旧目录并按字段推断 |
| `category` | 是 | 必须等于文件声明的 category |
| `title` | 是 | 短名 |
| `what` | 是 | 一句可观察的「测什么」 |
@@ -94,6 +95,18 @@ terminal;运行结束用 `orca terminal close --terminal <handle>` 关闭本
| `teardown` | 否 | 跑完回退 |
| `notes` | 否 | 备注 |
### 集成测试用例契约
`test_type: integration` 的用例不创建 browser/mobile session,也不能声明 `platform` 或
客户端 `journey`。必须有 `integration_suite`(迁移期可用 `suite`)且值为
`api-contract`、`authorization` 或 `build-contract`;`fixture` 必须是非空 mapping;
`request`、`input`、`call`、`integration` 之一或旧式 `how` 用于描述调用;`expected` 是
协议/数据断言。`mutating`/`destructive` 集成用例必须提供 `cleanup.steps` 或
`cleanup.run`(只读探针可用 `required: false` + `reason`)。
选择 `--suite api-contract` 或 `--test-type integration` 才会进入集成阶段;无显式类型
时的默认选择不会包含 integration。
### 客户端旅程用例契约
声明 `client_suite` 后,以下字段都必须存在;`catalog.py validate` 和 `select` 使用同一