TestContainer導入のリアル - 成功と課題、そして次のステップ
はじめに
こちら、Kyash Advent Calendar 2024の15日の記事です。 この記事は、TestContainerを導入し、Mockの脱却を図る試みを記事にしたものです。 実体験を元に、Kyash内部でどう悩み、テストの自動化を推進してきたかをお話ししていきます。
Mock依存の現状とその限界
Kyashでの開発にJOINしてから、日々の開発フローで自動テストの不足を強く感じておりました。特にMockテストが中心で、リアルなデータベース(DB)やメッセージキュー(SQS)のテストが行われておらず、AWS環境へのデプロイを待たなければ 本番環境に近い動作確認ができない状況は、 結果的に修正の数だけデプロイを強いられる環境に必然的になっておりました。
さらに、この開発サイクルでは、セキュリティチェックやCI/CDパイプラインを何度も通過する事になり、エンジニア及びCIの負荷を増加させ、開発スピードを著しく低下させる大きな要因となっていました。 開発負荷の増加はエンジニアのモチベーション低下にもつながります。
「このままではいけない」と、よりリアルなテスト環境の構築とその自動化を目指すべきでは?と考えました。
下記にMock依存の現場 図1を示します。
下記にリアルな自動テストを導入した際の現場 図2を示します。
上記の図をみて頂くと分かる通り、改修した後の失敗を短いスパンで達成できます。
誰にでもミスはあり、バグを混入するリスクはあります。それを最小限に抑えるのが上記の構成なのです。さらにMockでは、実際にDBやメッセージキューを起動するわけではないので、図1のようにデプロイ後に発覚するエラーが多発します。
過去の経験からの気づき
Tech Leadとして過去に担当したプロジェクトでは、Mockだけではなく、リアルなDBやSQSを用いたテスト環境を整備し、テスト自動化を実現していました。 これにより、開発効率が大幅に改善された経験があります。その成功事例から、「Kyashでも同じことができれば、開発サイクルを大幅に改善できる」と考えておりました。 ただし、Kyashのような金融系の大規模マイクロサービス環境で、どのようにして自動テストの導入を進めるかが次の課題となりました。
TestContainerによるリアルなテストの可能性
解決策として注目したのが、TestContainerの導入でした。 TestContainerを用いれば、リアルなDBやSQSをローカル環境でコンテナとして立ち上げ、Mockでは再現が難しい「本番に近い環境」をエミュレートできます。
これにより、手動デプロイを必要としない迅速な動作確認が可能となります。 さらに、これをCI/CDパイプラインに組み込むことで、デプロイ前に本番同等の統合テストを自動実行し、品質の向上が期待できると考えました。
下記にMockとTestContainerを導入した際の環境比較 図3を示します。
マイグレーションとブランチ管理の課題
しかし、TestContainerの導入を進める中で、大きな課題が浮上しました。
それはマイグレーションの管理とブランチの整合性です。
DBマイグレーション用のリポジトリと本体コードのリポジトリが分離しており、さらに共有DBと個別DBが混在していたため、ブランチ間の依存関係を管理するのが非常に困難でした。
これに対処するため、自動マイグレーションのスクリプトを作成し、開発ブランチとマイグレーションブランチを同期させるフローを構築することで、手動管理の手間を解消しました。
リアルなテストの強化と成果
導入後は、リポジトリ、ユースケース、ハンドラーといったDDD(ドメイン駆動設計)の各層ごとにテストを分け、統合テストを自動化しました。 DBスキーマの変更が発生すると、すぐにテストが失敗するよう設計し、コードとDBの整合性チェックを強化しました。 この仕組みのおかげで、実装ミスや変更漏れをMockテストだけに頼らず、DBレベルでの不整合も確実に検出できるようになり、開発の信頼性が大幅に向上しました。
Mockとリアルなテストの共存
すべての箇所をリアルなテストに置き換えるのではなく、Mockを使うべき場面を明確化しました。 たとえば、外部APIエンドポイントはMock化し、DB操作や内部システム間の連携テストにはTestContainerを使用しました。 このハイブリッドなアプローチにより、Mockの利点を活かしつつ、テストの正確性も高められました。 特に、SQSのように通常はローカル環境で再現が難しいリソースも簡単に模擬できるようになった点は、開発効率の大幅な向上につながりました。
成功事例と成果の積み重ね
TestContainerの導入は、最初は1つのマイクロサービスから始まりました。その後、複数のマイクロサービスに展開する中で、各サービス間の依存関係を考慮しつつ、E2Eテストの範囲を徐々に広げました。この取り組みにより、リグレッションテストの精度が飛躍的に向上しました。特に、デプロイの無駄な時間が削減され、開発者からは「信頼できるソースコードを素早く提供できるようになった」といった声が聞かれるようになりました。
具体的には、とある機能で障害が発生した際、テストコードが十分に整備されていたおかげで、システマチックに原因を特定することができました。このように、テスト結果が信頼性の根拠としてチーム全体に共有されていたため、問題解決の迅速化につながりました。
TestContainerを導入する前は、修正のたびにデプロイが必要で、エラーの原因究明に数日を要することも少なくありませんでした。しかし現在では、デプロイ前にほぼすべてのエラーを検出できるようになり、修正のリードタイムが大幅に短縮されています。また、コード変更によるテスト失敗時には問題箇所を即座に特定できるようになり、未検出のバグも激減しました。これにより、テストの網羅性が向上し、デプロイの成功率も目に見えて改善されています。
さらに、QAやシナリオテストにおいても、切り戻しの頻度が大幅に減少しました。この効果は、チーム全体が「エラーの早期検出が可能になり、安心してデプロイできる環境が整った」という実感を共有する形で表れています。TestContainerの導入は、開発サイクルの効率化と信頼性の向上を同時に実現し、開発プロセス全体の大きな進化につながりました。
今後の課題と改善目標
現在の自動テスト環境は多くの成果を上げましたが、まだ改善の余地があります。 特に、テストの並列化による実行時間の短縮は、次なる重要な課題です。 大規模なDBやマイクロサービスが連携するテストでは、処理が重くなるため、負荷分散やリソースの効率化が求められます。 また、さらなる信頼性向上のため、Newmanによるシナリオテストを統合できれば、リグレッションテストが漏れなく、実行でき、リファクタリングを高頻度に実行できます。 この施策の結果、私は、複雑なマイクロサービスでも自動テストの導入を行いシステム開発効率を向上させられることがわかりました。
最後に
KyashへJOINしてからもう9ヶ月ですが、様々な施策を行ってきました。今回は特に注力したリアルなテストの自動化についてお送りさせていただきました。 今後は、マイクロサービス間の自動テスト化をさらに発展させ、シナリオレベルで自動化するような施策を考えているので、来年もより高度なプロダクト開発を頑張りたいと思います!
Kyashでは、テストの拡充意外にも興味深い、技術的な挑戦を行なっています!
技術挑戦は多岐に渡り、外部との複雑な決済連携やクレジットカードの暗号化技術、マイクロサービス間のトランザクションの管理の方法など、日々、課題に対し真摯に向き合っています。
是非是非ご興味のある方はこちらからお申し込みを!!
Discussion