我的 CI/CD 流水线通过了 3 个月——直到我查看了日志

看到绿色的勾选标记感觉很棒。每一个 pull request 都通过了。每一次部署都成功了。

接着,一名用户报告了一个功能故障。它已经坏了好几周了。

我打开了流水线日志。我们那些显示“通过”的构建在欺骗我们。

我们的流程看起来很完美:

  • Linting
  • 单元测试 (Unit tests)
  • 集成测试 (Integration tests)
  • 构建 (Build)
  • 部署 (Deploy)

几个月来,每一步的成功率都是 100%。

点击导出按钮时没有任何反应。没有出现任何错误。我将其追溯到 11 周前的一次变更。流水线通过了。代码审查 (code review) 也通过了。但该功能从一开始就是坏的。

问题不在于我们的代码,而在于我们的测试代码。

我们的集成测试对所有内容都使用了 mock。我们 mock 了整个导出服务。测试检查的是 mock 对象,而不是真实的代码。mock 总是返回成功状态。

我们陷入了“过度 mock”的陷阱:

  • 单元测试:为了隔离单元而 mock 一切。这没问题。
  • 集成测试:为了速度而 mock 一切。这是一个错误。
  • E2E 测试:漏掉了这个特定的流程。

我们的集成测试只不过是昂贵的单元测试。它们验证了我们的 mock 是否工作,而不是验证我们的代码是否工作。

我做了三项改动来修复这个问题:

  1. 将 mock 限制在单元测试中。集成测试必须访问真实的数据库、API 和文件系统。如果测试运行缓慢,不要用 mock 来掩盖它。要把这种速度作为优化的信号。

  2. 增加契约测试 (contract tests)。这些测试可以确保你的 mock 与真实服务的行为一致。如果 mock 返回了真实服务不会返回的数据,契约测试就会失败。

  3. 追踪真实的覆盖率。我们不再只看简单的通过率,而是看测试实际执行了哪些内容。我们的覆盖率从 94% 降到了 67%。这是我们拥有的最诚实的指标。

流水线显示绿色并不意味着你的代码可以正常工作。它只意味着你的测试通过了。这两者是不同的。

最危险的 Bug 是那些流水线认为没问题的 Bug。

问问你自己这些问题:

  • 我的测试是在捕捉 Bug,还是仅仅在确认 mock 是否工作?
  • 我的集成测试真的实现了“集成”吗?
  • 如果我移除所有的 mock,还有多少测试能通过?
  • 我衡量的是覆盖率,还是信心?

一个永不失败的流水线是不可靠的。它根本没有经过测试。

来源:https://dev.to/kollittle/my-cicd-pipeline-passed-for-3-months-then-i-read-the-logs-4mbj