Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Turning a Broken Test Suite into a Deploy Gate

2026年10月19日に「Dev.to」が公開したITニュース「Turning a Broken Test Suite into a Deploy Gate」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

大量に失敗していたテストスイートを修正し、実行時間を短縮した事例。テストがパスしないとデプロイできない「デプロイゲート」を導入し、不安定だった開発プロセスを改善。GitHub Actionsへ移行することで、より安全で信頼性の高いデプロイを実現した。

ITニュース解説

このプロジェクトは、テストスイートが破損しているにもかかわらず本番環境へのデプロイが継続されていた状況を改善し、テストをデプロイゲートとして機能させるまでの過程を示している。NestJS APIのテストスイートは、87あるうち71が失敗していた。この問題は、開発パイプラインのどこにもテスト実行ステップがなかったため、誰も気づかないまま放置されていた。

問題の核心は、Cloud Buildの設定がイメージのビルドとデプロイの2ステップしか含んでおらず、テストが全く実行されていなかったことにあった。全体で218のテストがあったが、90が失敗しており、そのほとんどが「Nestが依存関係を解決できない」というエラーであった。特に、以前は動作していたレンタルサービス関連の重要なテストも、新しい依存関係が追加されてから機能しなくなっていたが、多数の失敗に埋もれて見過ごされていた。

開発者はこの状況に対処するため、まず壊れたテストの整理に着手した。失敗していた71のスイートを調査した結果、69のスイートがNest CLIによって自動生成された「should be defined」テストであることが判明した。これらのテストは、サービス自体は提供されるものの、その依存関係がモックされていなかったため、生成された時点から失敗していた。これらはコードの実際の振る舞いを検証するものではなく、Nestがクラスを正しく設定できるかを確認するだけのスタブテストであった。このようなスタブを維持するには、依存関係が変わるたびに手動でモックリストを更新する手間が必要であり、そのメンテナンスが69回も行われていなかったのが現状である。開発者はこれらのスタブテストがコードに関する有用な情報を提供しないと判断し、ほとんどを削除することにした。

一方で、残りの2つのスイートと一部のスタブテストは、実際のビジネスロジックや振る舞いを検証する上で重要であった。レンタルサービスのテストとリスティングコントローラのテストがこれに該当し、これらは依存関係のモックを追加したり、特定のガードの動作を一時的に無効化したりすることで修正された。特にデータや権限を扱うモジュール(リスティング、レンタル、ユーザー、webhook、認証)に関するスタブテストは、早期警告としての価値を考慮し、少数のメンテナンスコストを許容して残し、修正された。また、製品の仕様変更に関連する一つのテストは、プロダクト側の決定を待つため、一時的にスキップされた。

これらの作業の結果、テストスイートは25スイートに減少し、155のテストがパスし、1つがスキップされる状態になった。テストの実行時間は、以前の335秒から95秒へと大幅に短縮された。また、テスト実行時にデータベースURLや認証情報などの秘密情報を必要としないように設定することで、CI環境からこれらの情報を分離することにも成功した。

テストスイートが健全になった後、デプロイパイプラインに「デプロイゲート」を導入した。Cloud Buildのビルドステップの前に、yarn install --frozen-lockfile && yarn test --ci --maxWorkers=2というNodejsのコマンドを実行するステップを追加した。これにより、テストが失敗した場合、イメージのビルドもデプロイも行われなくなり、問題のあるコードが本番環境にデプロイされることを防げるようになった。このデプロイゲートの導入後、実際にいくつかのステージングビルドがテストステップで停止した。これにより、ローカル環境では再現しなかったCloud Build環境特有の問題(Prismaクライアントがコンテナ内で生成されていなかった問題、Jestのメモリ不足、モジュールのインポート時に認証情報を読み込もうとしてクラッシュする問題)が発見され、迅速に修正することができた。

デプロイゲートは機能したが、Cloud Buildでのテスト実行にはまだ課題があった。Dockerファイルのビルドステージですでに依存関係がインストールされているにもかかわらず、テストステップで再度yarn installが実行されたり、テスト失敗がCloud Buildのログに埋もれてコミットのステータスとして明確に表示されない点などである。これらの問題を解決するため、テストの実行環境をGitHub Actionsへ移行することにした。

GitHub Actionsへの移行にはいくつかの考慮事項があった。まず、gcloud builds submitコマンドでテスト後の巨大なnode_modulesディレクトリをアップロードするのではなく、gcloud builds triggers runコマンドを使ってCloud BuildにGitHubから直接ソースコードを取得させるようにした。これにより、不要なファイルのアップロードとビルド時間の増大を防いだ。次に、テスト実行中に新しいコミットがプッシュされた場合、古いテスト結果で新しいコードがデプロイされるリスクがあったため、--sha=${{ github.sha }}オプションを使って、テストをパスした特定のコミットのみをビルド・デプロイするように制御した。また、デプロイの順序が保証されるよう、GitHub Actionsのワークフローで並行処理グループを設定し、デプロイジョブがCloud Buildの完了を待つようにした。これにより、複数のコミットが短期間にプッシュされた場合でも、常に最新のテスト済みコミットがデプロイされるようになった。セキュリティ面では、GitHubに長期的なGCP認証鍵を置くリスクを避けるため、Workload Identity Federationを導入し、CIサービスアカウントに必要な最小限の権限のみを付与した。

パフォーマンス面では、GitHub ActionsのランナーがCloud Buildのマシンより低スペック(2vCPU)であったため、テスト実行時間が長くなるという予期せぬ問題が発生した。このため、テストスイートを3つのシャードに分割し、並行して実行することで実行時間を短縮した。いずれかのシャードが失敗した場合は、他のシャードとデプロイジョブを直ちにキャンセルするように設定した。

これらの変更は、Cloud Buildのプッシュトリガーを無効化し、手動デプロイから段階的に移行するなど、慎重に進められた。最終的に、意図的に壊したテストをプッシュしてデプロイがブロックされることを確認し、また古いCloud Buildのテストステップを削除し忘れて二重にテストが実行されていた問題も発見・修正するなど、機能の検証も徹底的に行った。

最終的な成果として、導入前と比較して、失敗テストスイートは71から0に、テスト実行時間は335秒から95秒へと改善された。デプロイ前にテストが実行されるようになり、失敗はGitHubのコミットステータスに赤色のXで明確に表示されるようになった。CI環境に長期的なGCP認証鍵を置く必要もなくなり、セキュリティも向上した。本番環境へのデプロイ時間は、テストの追加により10分から12分に微増したが、これはテスト済みコードがデプロイされる信頼性の向上と引き換えに許容できる範囲である。テストスイート自体も、不要なスタブテストが削除されたことで、218テストから156テストへとスリム化された。この経験から、テストゲートはプロジェクトの初期段階で導入すべきであり、またCIランナーの実際のスペックに基づいてテスト計画を立てることが重要であるという教訓が得られた。

関連コンテンツ

関連IT用語