构建与测试自动化
核心问题
代码写完了,CodeReview 也过了,接下来要验证它能不能编译、测试能不能通过。Qoder 怎么帮我把"构建+测试"这条链路自动化?
在 Growth 项目中,构建和测试不是靠 IDE 点按钮,也不是靠 CI 推送代码后才知道结果——它们是通过 CLI 脚本 + Qoder Skill 实现的本地自动化。
使用篇:构建流程封装为 Skill
问题背景
Growth 产品由多个子项目组成,每次构建需要依次处理多个部分:
前端(Web/frontend — Rush monorepo,168 packages)
→ product-info 文档站(VitePress)
→ Desktop 桌面端(.NET Release 构建)
→ 资源复制到 publish/ 目录手动执行这些步骤既慢又容易出错。所以我们将构建流程封装为 Skill。
构建 Skill 设计
构建 Skill 不在 Qoder 的 Skill 目录里,而是包装了已有的 CLI 脚本:
markdown
---
name: build-growth
description: 一键构建 Growth AIOS 全部组件
---
步骤:
1. 执行 `.\package.ps1` — 全量构建(前端 + 文档 + 桌面端)
2. 如果指定 -Step,只构建对应部分
3. 输出到 publish/ 目录
4. 检查构建日志,确认是否有错误贯穿案例中的应用
"文件压缩节点"写完了,需要验证它能不能编译通过。你不需要手动执行构建命令,只需要说:
/build-growth desktopQoder 会自动执行 .\package.ps1 -Step desktop,读取构建日志,如果编译成功就告诉你,如果失败就分析错误日志定位根因。
分段构建的精髓
package.ps1 设计了一个很实用的功能——分段构建:
.\package.ps1 # 全量构建(5 步全走)
.\package.ps1 -Step frontend # 只构建前端
.\package.ps1 -Step desktop # 只构建 Desktop
.\package.ps1 -Step productinfo # 只构建文档站为什么需要分段?因为在迭代开发中,你通常只改了某个部分。如果你只改了 Desktop 的代码,根本不需要重新构建前端。
这也是 CLI 脚本的优势:你可以精确控制构建的范围。如果是通过 IDE 点按钮,通常只能全量构建。
使用篇:测试流程封装为 Skill
Growth 项目有一个独立的测试工程 Components.Test,它覆盖了 9 个核心模块的接口级验证。这个测试框架本身就是为了被 AI 调用而设计的——它的命令行参数化、数据目录契约、输出文件格式,都是可编程的、AI 可读的。
测试框架架构
测试框架采用模块化架构,每个被测模块对应一个测试模块(TestModule),通过统一的命令行接口触发:
Components.Test
├── TestRunnerHost.cs # 测试框架入口,解析命令行参数
├── Modules/ # 测试模块(按被测组件划分)
│ ├── WorkflowTestModule # 工作流测试
│ ├── WorkflowIntegrationTest # 工作流集成测试(从草稿加载)
│ ├── LLMTestModule # LLM 服务测试
│ ├── CLITestModule # CLI 服务测试
│ ├── NodeTestModule # 单节点测试
│ ├── CodeRunnerTestModule # 代码执行测试
│ ├── PluginTestModule # 插件测试
│ ├── TriggerTestModule # 触发器测试
│ └── VarVaultTestModule # 凭证管理测试
├── TestFramework/ # 测试运行器
│ ├── WorkflowTestRunner
│ ├── WorkflowIntegrationTestRunner
│ ├── LLMTestRunner
│ └── ...
└── TestCases/ # 测试用例数据
├── Workflow/
├── LLM/
└── ...模块化测试命令体系
每个测试模块注册了短参数和长参数,AI 可以通过 CLI 精确控制测试范围:
| 模块 | 短参数 | 长参数 | 作用 |
|---|---|---|---|
| 工作流测试 | -w | --workflow-test | 运行所有工作流测试 |
| 工作流集成 | -wi | --workflow-integration | 按草稿 ID 运行集成测试 |
| 单节点测试 | -n | --node-test | 运行单节点调试测试 |
| LLM 测试 | -l | --llm-test | 运行 LLM 服务测试 |
| CLI 测试 | -c | --cli-test | 运行 CLI 服务测试 |
| CodeRunner | -r | --coderunner-test | 运行代码执行测试 |
| Plugin | -p | --plugin-test | 运行插件测试 |
| Trigger | -t | --trigger-test | 运行触发器测试 |
| VarVault | -vv | --varvault-test | 运行凭证管理测试 |
所有模块还支持指定具体场景(如 -wi 28 表示运行草稿 ID 为 28 的集成测试,-l basic_chat 表示运行基础对话的 LLM 测试)。
测试 Skill 设计
测试 Skill 不直接封装测试框架的调用方式,而是告诉 AI 如何利用这个 CLI 框架完成测试任务。这是一个真实的 Skill 模板:
markdown
---
name: workflow-integration-test
---
## 测试目的
对指定草稿 ID 的工作流执行集成测试,验证执行成功并检查数据库状态
## 步骤
### 1. 准备测试数据
确认测试目录 `TestCases/Workflow/IntegrationByDraft/{DraftId}/` 下有 `input.json`,
包含工作流的输入参数。
### 2. 编译测试项目
```bash
dotnet build Components.Test3. 运行集成测试
bash
dotnet run --project Components.Test -- -wi {DraftId}4. 验证 execute_log.txt
读取 TestCases/Workflow/IntegrationByDraft/{DraftId}/execute_log.txt, 确认日志中包含 "通过" 或 "success",确认所有节点状态为 Completed。
5. 验证 output.json
读取 output.json,确认 Status 为 "Complete",IsSuccess 为 true。
6. 查询数据库状态(可选)
查询 workflow_instance 表,确认实例状态为 1(完成), 记录条数和执行时长符合预期。
### 贯穿案例中的应用
"文件压缩节点"写完了,需要验证它在一个真实工作流中的表现。对应的草稿已经在数据库中保存。你只需要说:/workflow-integration-test 28
Qoder 会自动编译测试项目,运行草稿 28 的工作流集成测试,然后检查 execute_log.txt 确认所有节点执行成功,读取 output.json 确认输出路径正确,最后查询数据库确认工作流实例已完成。整个过程不需要你打开 IDE 或数据库客户端。
---
## 实践篇:测试数据即契约
测试 Skill 的核心是对测试数据的操作。Components.Test 定义了一套标准的数据契约,让 AI 可以读取输入、解析输出、验证结果。
### 标准数据契约TestCases/{Module}/{Scenario}/ ├── input.json # 测试输入(手动编写) ├── output.json # 测试输出(运行时生成) ├── execute_log.txt # 执行日志(运行时生成,可能很大) ├── trace.txt # Trace 摘要(运行时生成) ├── trace.json # Trace 详情(运行时生成) ├── route.txt # 执行路由(运行时生成) ├── flowchart.md # 流程图(运行时生成) └── report.md # 测试报告(运行时生成)
每个文件有明确的角色:
| 文件 | 谁写的 | 给谁看 | 用途 |
|------|--------|--------|------|
| `input.json` | 开发者 | AI | 告诉测试框架这次测什么参数 |
| `output.json` | 框架 | AI | 结构化的执行结果,JSON 格式,AI 可精确解析 |
| `execute_log.txt` | 框架 | 人类 + AI | 详细的执行日志,AI 搜关键词做断言 |
| `trace.txt` | 框架 | 人类 | 缩进格式的 Trace 摘要,一眼看到执行顺序 |
| `flowchart.md` | 框架 | 人类 | Mermaid 流程图,可视化工作流拓扑 |
| `report.md` | 框架 | 人类 | 完整的测试报告,含节点执行详情 |

### 真实案例:Draft#28 测试数据
以草稿 28 的工作流集成测试为例,我们来拆解测试数据是如何被消费的。
**input.json** —— 告诉测试框架输入参数:
```json
{
"inputa": "C:\\Users\\renyu\\Videos\\Captures\\test",
"inputb": "",
"inputc": []
}这个工作流搜索指定目录下的视频,然后对每个视频进行裁剪(去头尾)。三个参数分别对应:搜索路径、过滤条件、排除列表。
output.json —— 结构化输出:
json
{
"DraftId": 28,
"Status": "Complete",
"IsSuccess": true,
"DurationMs": 4544,
"Output": {
"output1": [
"C:\\Users\\renyu\\Videos\\Captures\\test\\...\\cover_trimmed.mp4",
"C:\\Users\\renyu\\Videos\\Captures\\test\\...\\trimmed.mp4"
],
"Status": "Complete"
}
}AI 读取这个 JSON,不需要解析自然语言就能确认:
- 工作流执行成功(
Status: "Complete") - 输出包含两个视频文件路径
- 总耗时 4.5 秒
trace.txt —— 层级化执行摘要:
Workflow: 4fdb39aa-68bb-40bc-8336-db9a8f3a75e2
Start: 2026-05-12 08:31:41.008
Complete: 2026-05-12 08:31:45.039
Duration: 4031ms
============================================================
✔ [1] 开始 (100001) 59ms
✔ [FileSearch] FileSearch (181897) 548ms
✔ [21] 循环 (148928) 2751ms
✔ [VideoTrim] 裁剪头尾 (193753) [迭代 0] 1505ms
✔ [VideoTrim] 裁剪头尾 (193753) [迭代 1] 2746ms
✔ [2] 结束 (900001) 7ms缩进反映了节点间的嵌套关系:循环节点内部有两个迭代,每个迭代执行视频裁剪。AI 可以通过缩进结构判断执行流程是否完整。
两级验证体系
测试 Skill 的验证分为两级:
第一级:日志验证(轻量级,必做)
AI 读取 execute_log.txt,用关键词匹配做断言:
- 搜索 "success": True 或 "通过",确认整体成功
- 搜索 "Completed",确认节点状态
- 搜索 "Error" 或 "Exception",确认无异常
第二级:数据库验证(重量级,可选)
当需要更精确的验证时,AI 可以直接查询 CozeServer 数据库:
sql
-- 查询工作流实例状态
SELECT Id, Status, StartedAt, CompletedAt, DurationMs
FROM workflow_instance
WHERE Id = '4fdb39aa-68bb-40bc-8336-db9a8f3a75e2'Status 字段的值映射:0=Pending(等待中)、1=Running(运行中)、2=Complete(已完成)、3=Failed(失败)、4=Cancelled(取消)。
验证流程用伪代码描述就是:
验证工作流(wfId, draftId) {
// 第一步:验证日志
log = 读取 execute_log.txt
断言 log 包含 "通过"
断言 log 不包含 "Error"
// 第二步:验证 output.json
output = 读取 output.json
断言 output.Status == "Complete"
断言 output.IsSuccess == true
// 第三步:验证数据库(可选)
status = db.query("SELECT Status FROM workflow_instance WHERE Id = ?", wfId)
断言 status == 2 // Complete
返回 验证通过
}这个两层验证设计很实用——日志验证快速直观,数据库验证精确可靠。大部分场景下,第一级就足够了。
实践篇:脚本即基础设施
脚本不只是"辅助工具"
在很多项目中,构建脚本是"写了就不管"的东西——只要能跑通就行,没人关心它写得好不好。
但在 Growth 项目中,构建脚本被当作基础设施来对待。
看看 package.ps1 的设计:
powershell
# 分段构建 - 按需执行
param(
[ValidateSet('all','frontend','productinfo','desktop')]
[string]$Step = "all",
[string]$OutputDir = ""
)
# 每个步骤独立运作,只清理和替换自己对应的部分
switch ($Step) {
"all" {
Build-Frontend
Build-ProductInfo
Build-Desktop
Copy-Resources
Print-Summary
}
"frontend" { Build-Frontend }
"productinfo" { Build-ProductInfo }
"desktop" { Build-Desktop }
}这个设计有三个特点:
- 参数化 — 通过
-Step参数控制构建范围,不是写死的全量构建 - 模块化 — 每个构建步骤是独立函数,可以单独调用
- 可组合 — 全量构建就是依次调用各个步骤
为什么"脚本即基础设施"对 AI 重要
当脚本本身是良好设计的基础设施时,Qoder 可以做三件事:
| 能力 | 怎么做 | 效果 |
|---|---|---|
| 读取 | AI 直接读取脚本内容 | 理解构建流程,不需要额外文档 |
| 执行 | AI 调用脚本 | 构建自动化,不需要 IDE 操作 |
| 排错 | 脚本失败时 AI 分析日志 | 快速定位根因 |
如果构建逻辑藏在 IDE 的配置里或者 CI 的流水线里,Qoder 就无法读取、无法执行、无法排错。
对比视角:Java 项目为什么做不到
Java 项目通常依赖 IDE 或 CI 来构建和测试:
| 环节 | Java 项目 | Growth 项目 |
|---|---|---|
| 本地构建 | IDE 点 Maven 插件 | .\package.ps1 |
| 分段构建 | 手动排除模块 | -Step desktop |
| 测试 | IDE 点运行 | /test-component |
| 构建失败处理 | 看 IDE 输出窗口 | AI 自动分析日志 |
区别的根本原因不是技术,而是工程文化——Java 开发者习惯通过 IDE 操作,不太考虑"脚本化"这件事。
知识篇:为什么 CLI 脚本比 IDE 操作更适合 AI 编排
可编程 vs 可视化
IDE 操作本质上是可视化的——点按钮、看输出、翻日志。这些操作对人类来说很自然,但对 AI 来说无法直接执行。
CLI 脚本本质上是可编程的——参数化的命令、结构化的输出、明确的退出码。这些对 AI 来说天然友好。
封闭循环
脚本 + AI 形成一个封闭循环:
AI 生成脚本 → AI 执行脚本 → AI 读取输出 → AI 分析结果 → AI 决定下一步整个循环不需要人类介入。如果构建失败,AI 分析日志、定位问题、修正代码、重新构建——这是一个完全自动化的闭环。
而 IDE 操作是开放循环:
人类点按钮 → 看 IDE 输出 → 人类分析日志 → 人类决定下一步人类的介入打断了自动化流程。
本章小结
| 能力 | 工具 | 对贯穿案例的作用 |
|---|---|---|
| 构建自动化 | 构建 Skill + package.ps1 | 验证节点编译通过 |
| 测试自动化 | 测试 Skill + Components.Test | 按草稿 ID 运行集成测试 |
| 失败分析 | AI 读取构建/测试日志 | 定位构建失败根因 |
| 测试数据契约 | input.json / output.json / trace.txt | AI 可读的结构化测试数据 |
| 两级验证体系 | 日志关键词断言 + SQL 状态查询 | 验证节点功能正确 |
| 脚本基础设施 | 良好设计的 CLI 脚本 | AI 可读、可执行、可排错 |
关联:第二部分 03(技能沉淀)。