Skip to content

构建与测试自动化

核心问题

代码写完了,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 desktop

Qoder 会自动执行 .\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.Test

3. 运行集成测试

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` | 框架 | 人类 | 完整的测试报告,含节点执行详情 |

![测试数据契约体系](/assets/concept/04/05-test-data-contract.png)

### 真实案例: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 }
}

这个设计有三个特点:

  1. 参数化 — 通过 -Step 参数控制构建范围,不是写死的全量构建
  2. 模块化 — 每个构建步骤是独立函数,可以单独调用
  3. 可组合 — 全量构建就是依次调用各个步骤

为什么"脚本即基础设施"对 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.txtAI 可读的结构化测试数据
两级验证体系日志关键词断言 + SQL 状态查询验证节点功能正确
脚本基础设施良好设计的 CLI 脚本AI 可读、可执行、可排错

关联:第二部分 03(技能沉淀)。