3ヶ月間、CI/CDパイプラインは成功し続けていた —— それで、ログを読んでみた

緑色のチェックマークは気持ちがいい。すべてのプルリクエストがパスし、すべてのデプロイが成功した。

しかし、あるユーザーから機能の不具合が報告された。それは、数週間前から壊れていたのだ。

パイプラインのログを開いた。成功し続けていたビルドは、私たちに嘘をついていた。

私たちのプロセスは完璧に見えた:

  • リンティング
  • ユニットテスト
  • 結合テスト
  • ビルド
  • デプロイ

数ヶ月間、すべてのステップで成功率100%を維持していた。

エクスポートボタンをクリックしても何も起きなかった。エラーすら表示されない。原因を辿っていくと、11週間前の変更に突き当たった。パイプラインはパスしていた。コードレビューも承認されていた。その機能は、最初から壊れていたのだ。

問題はコードではなかった。テストコードにあった。

私たちの結合テストは、あらゆるものにモックを使用していた。エクスポートサービス全体をモック化していたのだ。テストは実際のコードではなく、モックを検証していた。そして、そのモックは常に成功ステータスを返していた。

私たちは「過剰なモック化」という罠に陥っていた:

  • ユニットテスト:ユニットを分離するためにすべてをモック化する。これは問題ない。
  • 結合テスト:速度を優先してすべてをモック化する。これは間違いだ。
  • E2Eテスト:この特定のフローを見逃していた。

私たちの結合テストは、単にコストの高いユニットテストに過ぎなかった。それらは「モックが正しく動作するか」を検証していただけで、「コードが正しく動作するか」を検証していなかったのだ。

これを修正するために、3つの変更を行った:

  1. モックの使用をユニットテストに限定する。結合テストでは、実際のデータベース、API、ファイルシステムにアクセスしなければならない。テストが遅い場合、モックでそれを隠してはいけない。その遅さを、最適化すべきシグナルとして捉えるべきだ。

  2. コントラクトテストを追加する。これにより、モックが実際のサービスの振る舞いと一致していることを保証できる。もしモックが実際のサービスではありえないデータを返した場合、コントラクトテストが失敗する。

  3. 真のカバレッジを追跡する。単なるパス率を見るのをやめた。テストが実際に何を検証しているかに注目した。その結果、カバレッジの数値は94%から67%に低下した。これが、私たちにとって最も誠実な指標だった。

パイプラインが緑色であることは、コードが動作することを意味しない。それは単に「テストがパスした」ことを意味しているに過ぎない。この二つは別物だ。

最も危険なバグとは、パイプラインが「問題なし」と判定するものだ。

以下の問いを自分自身に投げかけてみてほしい:

  • 私のテストはバグを見つけているか、それとも単にモックを確認しているだけか?
  • 私の結合テストは、本当に「結合」しているか?
  • もしすべてのモックを削除したら、いくつのテストがパスするか?
  • 私はカバレッジを測っているのか、それとも信頼性を測っているのか?

決して失敗しないパイプラインは、信頼できるものではない。それは「テストされていない」のだ。

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