3ヶ月間、CI/CDパイプラインは成功し続けていた —— それで、ログを読んでみた
緑色のチェックマークは気持ちがいい。すべてのプルリクエストがパスし、すべてのデプロイが成功した。
しかし、あるユーザーから機能の不具合が報告された。それは、数週間前から壊れていたのだ。
パイプラインのログを開いた。成功し続けていたビルドは、私たちに嘘をついていた。
私たちのプロセスは完璧に見えた:
- リンティング
- ユニットテスト
- 結合テスト
- ビルド
- デプロイ
数ヶ月間、すべてのステップで成功率100%を維持していた。
エクスポートボタンをクリックしても何も起きなかった。エラーすら表示されない。原因を辿っていくと、11週間前の変更に突き当たった。パイプラインはパスしていた。コードレビューも承認されていた。その機能は、最初から壊れていたのだ。
問題はコードではなかった。テストコードにあった。
私たちの結合テストは、あらゆるものにモックを使用していた。エクスポートサービス全体をモック化していたのだ。テストは実際のコードではなく、モックを検証していた。そして、そのモックは常に成功ステータスを返していた。
私たちは「過剰なモック化」という罠に陥っていた:
- ユニットテスト:ユニットを分離するためにすべてをモック化する。これは問題ない。
- 結合テスト:速度を優先してすべてをモック化する。これは間違いだ。
- E2Eテスト:この特定のフローを見逃していた。
私たちの結合テストは、単にコストの高いユニットテストに過ぎなかった。それらは「モックが正しく動作するか」を検証していただけで、「コードが正しく動作するか」を検証していなかったのだ。
これを修正するために、3つの変更を行った:
モックの使用をユニットテストに限定する。結合テストでは、実際のデータベース、API、ファイルシステムにアクセスしなければならない。テストが遅い場合、モックでそれを隠してはいけない。その遅さを、最適化すべきシグナルとして捉えるべきだ。
コントラクトテストを追加する。これにより、モックが実際のサービスの振る舞いと一致していることを保証できる。もしモックが実際のサービスではありえないデータを返した場合、コントラクトテストが失敗する。
真のカバレッジを追跡する。単なるパス率を見るのをやめた。テストが実際に何を検証しているかに注目した。その結果、カバレッジの数値は94%から67%に低下した。これが、私たちにとって最も誠実な指標だった。
パイプラインが緑色であることは、コードが動作することを意味しない。それは単に「テストがパスした」ことを意味しているに過ぎない。この二つは別物だ。
最も危険なバグとは、パイプラインが「問題なし」と判定するものだ。
以下の問いを自分自身に投げかけてみてほしい:
- 私のテストはバグを見つけているか、それとも単にモックを確認しているだけか?
- 私の結合テストは、本当に「結合」しているか?
- もしすべてのモックを削除したら、いくつのテストがパスするか?
- 私はカバレッジを測っているのか、それとも信頼性を測っているのか?
決して失敗しないパイプラインは、信頼できるものではない。それは「テストされていない」のだ。
Source: https://dev.to/kollittle/my-cicd-pipeline-passed-for-3-months-then-i-read-the-logs-4mbj
