CI流水线中的回归流程:触发机制、阶段划分、结果收集与存储

回归测试不是拍脑袋就能跑的。你得想清楚:什么时候触发?跑哪些阶段?结果怎么掏出来存好?这套流程我改过不下十次,今天把最稳的方案摊开聊。

1. 回归测试的触发机制

触发方式就两大类:自动触发和手动触发。但具体怎么设,坑不少。

  • 自动触发:
    • 代码 push 到特定分支(如 main、release/、hotfix/)
    • 定时触发(凌晨跑全量回归,白天跑增量)
    • 依赖更新(比如上游库升级,自动触发下游回归)
  • 手动触发:
    • PR 合并前「单击」
    • 上线前人工审批触发
    • debug 时临时重跑指定 case

关键原则:轻量级高频触发 + 重量级低频触发。commit 级只跑影响模块的 smoke test,凌晨跑全量。

我遇到过什么情况?有个项目把所有 commit 都触发了全量回归,跑了 2 小时。开发往 git 里改个空格,全组等着。后来改成「push 触发增量单元测试 + 每晚定时全量」,资源占用直接降 70%。

⚠ 注意:别把触发条件写得过于严格。比如只允许 merge 到 main 才触发,那 feature 分支的 bug 要等到最后才暴露——早晚出大事。

2. 回归阶段的划分

流水线里的阶段就像安检口,一层层筛问题。我习惯把回归分成四个核心阶段:

  1. 编译构建阶段:检查代码能否编译通过,依赖是否一致。
  2. 单元测试阶段:跑快速的小粒度的测试,通常 5 分钟内完成。
  3. 集成测试阶段:模块之间交互,包括接口、数据库、消息队列。
  4. 端到端测试阶段:全链路模拟用户操作,成本最高,放最后。

每个阶段都配一个「门禁」。前一个阶段失败,后面直接跳过。这一点我吃过亏——有次集成测试跑了 40 分钟,结果发现是单元测试输入的参数类型不对。后来我强制要求:阶段失败后立即中止流水线,并发送通知。

阶段典型时长门禁条件
编译构建1~3 min编译错误 → 终止
单元测试3~10 min失败率 > 0% → 终止
集成测试10~30 min核心接口失败 → 终止
端到端测试20~60 min关键场景失败 → 终止

💡 如果你用 Jenkins,可以用 parallel 把独立模块的测试并行跑,但注意资源上限。我一般给每个阶段设 10 个并行执行器,超出就排队。

3. 结果收集与存储

结果收集这块容易「捡了芝麻丢西瓜」。我曾见过团队只存储 pass/fail 标志,想查失败日志还得翻 Jenkins 控制台——太原始了。

标准做法是:每个阶段结束时,把以下关键数据结构化输出:

  • 测试用例总数、通过数、失败数、跳过数
  • 失败用例的全栈日志(stack trace)
  • 执行耗时(总耗时 & 每个用例耗时)
  • 代码覆盖率(行覆盖、分支覆盖)
  • 关联的 commit hash、branch、trigger 类型

存储我用两套方案:

  • 关系数据库(比如 PostgreSQL):存元数据,如流水线 ID、状态、耗时、统计摘要。方便查历史趋势。
  • 对象存储(比如 MinIO 或 S3):存原始日志、截图、报告 HTML。按 pipeline_id/stage_name/test_case_xxx.log 组织。

为什么分开?元数据要支持快速查询和聚合,日志文件太大不适合放数据库。有一次我们要查一个月内所有失败用例的模式,直接 SQL 就搞定了,不用解压日志。

4. 结果收集与存储的典型模型

-- 简化的流水线结果表结构
CREATE TABLE pipeline_results (
    id BIGINT PRIMARY KEY,
    project VARCHAR(64),
    branch VARCHAR(128),
    commit_sha CHAR(40),
    trigger_type VARCHAR(20),   -- push | manual | scheduled
    status VARCHAR(20),         -- passed | failed | aborted
    total_duration_sec INT,
    stage_summary JSONB,        -- 各阶段统计
    created_at TIMESTAMPTZ
);

CREATE TABLE test_case_results (
    id BIGINT PRIMARY KEY,
    pipeline_id BIGINT REFERENCES pipeline_results(id),
    stage VARCHAR(32),
    test_name VARCHAR(256),
    status VARCHAR(20),
    duration_ms INT,
    failure_text TEXT,
    log_path VARCHAR(512),      -- 指向对象存储的路径
    created_at TIMESTAMPTZ
);

⚠ 务必给 pipeline_id 和 created_at 建索引。我见过有人没加索引,查一个月数据要扫 500 万行——跑了 30 秒。

结果收集完了,怎么用?我一般在流水线最后一步加一个「分析汇总动作」:

  • 如果失败率 > 5%,自动创建 Jira ticket 并 @ 责任开发者。
  • 如果关键场景失败,直接阻止合并。
  • 每天早会前,自动发一份回归健康度报告到团队群。

还有一个小技巧:记录每次回归的「执行快照」,包括依赖版本、环境变量、执行时间。这样出现不稳定测试时,我可以回溯上次通过的环境配置。说白了,回归结果不只是红绿,它要能支撑 debug。

回归流水线核心流程 触发 push / 定时 / 手动 编译 & 单元测试 快速验证(<5min) 集成测试 接口、数据库、MQ 端到端测试 用户全链路 结果收集 元数据+日志+报告 结果分析 & 通知 门禁 / Jira / 报告 流水线阶段 自动/手动触发 DB + 对象存储

说实话,这套流程我磨合了将近一年,才形成现在的模板。你刚开始可能会觉得「阶段太多,结果太细」,但一旦线上出故障,这些数据就是你定位问题的救命稻草。试着跑一次,迭代两三次,你就能找到最适合自己团队的节奏。