PAYATHON 2026

在 continuous integration 中,何时运行 unit-tests 更合适?

技术老齐

建议分别设置本地开发和 CI 的测试要求。开发时按需运行相关 unit-tests,共享代码前运行完整单元测试。CI 则在每次推送或合并请求更新后自动验证;测试失败时,将该次 CI 构建标记为失败,并阻止合并。

本地编译和启动应用可以保留独立入口,不必每次启动都等待全部测试。团队共享分支应保持测试通过,出现失败后优先修复或回退,不能只发通知就长期搁置。

为什么要区分本地构建和 CI 构建

“编译成功”“应用能够启动”和“测试通过”回答的是不同的问题。构建工具既可以将这些任务串联起来,也可以让它们独立运行。

开发中暂时有测试失败很正常。例如,修改接口时,调用方和测试可能还没同步;采用 TDD 时,也会先写出失败的测试。如果每次运行应用前都必须通过全部测试,就会妨碍调试。

代码进入共享分支后,测试失败会影响其他开发者。他们需要在这个版本上继续工作;如果测试一直失败,就很难判断新问题是否由自己的改动造成。本地可以允许测试暂时失败,CI 则应如实报告验证结果,并通过合并规则控制失败代码何时进入共享分支。

如何安排测试时机

时机建议执行的测试失败后的处理
修改代码、调试时与当前改动相关的测试,可使用 IDE 或 watch 模式在当前开发过程中处理
准备共享改动前完整 unit-tests修复后再推送到共享分支;个人草稿分支可另行约定
推送或合并请求更新后CI 自动运行完整 unit-tests标记检查失败,阻止合并
合并进入主分支后验证合并后的版本若失败,优先修复或回退

“每次 commit 后运行”通常需要明确为“每次推送后运行”。只在本地创建 commit,远端 CI 通常不会收到事件。一次推送包含多个 commit 时,CI 是否逐个验证,也取决于触发配置。至少应验证准备合并的最新版本。

落地步骤

1. 提供独立的本地运行入口

让开发者可以单独编译、启动应用或运行测试,同时提供一个执行完整检查的入口。

如果现有工具的 build 生命周期已经包含测试,可以保留这个约定,另设开发用的编译或启动命令。命令名称由项目决定,但团队需要清楚每个命令实际执行哪些检查。

2. 在共享代码前完成本地检查

开发时先运行相关测试,缩短反馈时间;准备共享改动时,再运行完整 unit-tests,检查是否影响其他模块。

本地 hook 可以帮助执行检查,CI 仍需独立运行测试。本地环境和执行习惯各有差异,团队需要统一且可查看的验证结果。

3. 让 CI 失败产生明确后果

测试失败应使 CI 任务失败。采用合并请求的团队应把单元测试设为必需检查,只有目标版本通过后才允许合并。

如果多人直接向同一共享分支提交,提交后的 CI 就无法阻止失败代码先进入分支。这种工作方式需要更严格的提交前检查,也需要约定失败后的处理方式:由引入问题的人优先修复;无法及时修复时,回退相关改动,恢复可用基线。

合并检查还应考虑目标分支的变化。各分支分别通过测试,不代表合并后的版本一定通过。可以根据 CI 平台的能力验证合并结果,或要求更新到最新基线后重新检查。

一个任务拆分示例

这个 Makefile 示例假定项目已有对应脚本,且 unit-tests.sh 在测试失败时返回非零退出码。脚本名称需要替换为项目实际命令。

.PHONY: build unit-tests verify run

build:
	./scripts/build.sh

unit-tests: build
	./scripts/unit-tests.sh

verify: unit-tests

run: build
	./scripts/run.sh

本地调试时启动应用:

make run

共享代码前和 CI 中执行完整验证:

make verify

运行应用只依赖编译成功,完整验证则要求编译和单元测试都成功。CI 必须保留命令的失败状态,不能忽略测试错误后继续报告成功。

测试耗时和 integration-tests 怎么处理

如果完整 unit-tests 慢到开发者经常跳过,应先检查时间花在哪里:测试数量、重复初始化、外部服务依赖,还是执行方式。可以优先运行相关测试、隔离测试数据,或并行执行测试。并行执行的前提是测试之间没有共享状态冲突。

对于依赖数据库、网络或其他外部进程的测试,应重新检查分类,明确是否应放入 integration-tests 流程。测试类型不能仅凭耗时长短划分。

已有独立的 integration-tests 流程可以继续保留,但要明确哪些检查结果会阻止合并或发布。unit-tests 通过,只能说明这些单元测试覆盖的行为符合预期,不能替代集成验证。如果某项集成检查决定代码能否合并,就应等待对应版本的检查结果。

偶发失败的测试也要及时处理。确需临时隔离时,应指定负责人和修复期限,并让团队清楚隔离了哪些测试。反复重跑直到变绿,会让失败结果越来越难以判断。

备注:内容仅供参考。