🔍

マイクロサービスアーキテクチャに Integration Test を導入しました

2023/04/24に公開

こんにちは、バックエンドを中心に開発をしています、野島といいます。
今回は、スマートショッピングにおいて、Integration Test(統合テスト)を導入したのでこちらを紹介します。
弊社では、マイクロサービスアーキテクチャを採用しており、その中のテストのひとつとしてIntegration Testを導入しました。

Integration Testについて説明した後、なぜ導入することにしたのかについて書き、どのように実現しているのかという技術的なことを述べます。

Integration Test の本記事における定義

本記事では、Integration Testを以下のように定義します。

マイクロサービスが依存する外部コンポーネントをモック化せずに行うAPIテスト。
外部コンポーネントとは、具体的にはデータストア、外部サービス、テスト対象が依存するマイクロサービス、などを指します。
テスト対象のマイクロサービスが公開するAPI(WebAPI等)を介して自動テストを行います。

Integration Testという言葉は広範囲にわたり、イメージするものが人によって異なることが多いので、本記事での取り扱いを先に述べさせていただきました。
堅苦しく書きましたが、WebAPIの自動テストをするんだなぁ、テスト対象が依存するものは本物を使ってモック化しないんだなぁ、ぐらいに捉えていただければと思います。

なぜ Integration Test を導入するのか

次の理由があって、Integration Test導入を決意しました。

  • 弊社で発生した障害を振り返ると、APIレベルのテストが存在すれば防げるものがあった
  • Integration Testを導入することで複雑さに対応し、自信を持って開発・デプロイするために
  • テスト戦略を考えると、Integration Testの仕組みを導入したかった

弊社で発生した障害を振り返ると、APIレベルのテストが存在すれば防げるものがあった

弊社では、ポストモーテム共有会、という会を不定期に開催しています。
障害を振り返り、そこから学びを得ることを目的とした会です。
その中で、これはAPIレベルのテストが存在すれば防げたなぁ、と思う事象がいくつかありました。

同じような障害を繰り返すのはよろしくないです。
再発を防ぐには仕組みが必要です。
そこに、Integration Testがあれば、効きそうだと思い導入のきっかけのひとつになりました。

Integration Testを導入することで複雑さに対応し、自信を持って開発・デプロイするために

事業、ソフトウェアの成長とともに、複雑さが増してくることは避けられないでしょう。機能が増えるにつれて、ソフトウェアは複雑になっていきます。
これにどう対応するかといえば、テストを書くのが良いと考えています。

テストを書くことで、機能追加やリファクタリングの際に既存の振る舞いを壊さないことや、期待通りの動作になることを確認できます。正しいことをしているという自信を開発者に与えてくれて、安心してデプロイできます。デプロイ頻度を上げて開発速度を向上させるためには、テストが必要です。
テストはUTだけでカバーできない領域があるので、その範囲をIntegration Testでカバーするために導入のモチベーションがありました。

テスト戦略を考えると、Integration Testの仕組みを導入したかった

テストピラミッドという概念があります。
この中で、E2E,UTの仕組みはすでにあるのですが、Integration Testはなかったので導入したいという気持ちを高めました。

テストピラミッドの画像

詳しい解説はchat gpt先生にお願いしました。

chat gpt によるテストピラミッドについて解説の画像1
chat gpt によるテストピラミッドについて解説の画像2

Integration Test の技術面でのお話

採用した技術

CIにテストを組み込むのに、Argo Workflows を利用し、
テストケース自体は、scenarigo で実装します。

Argo Workflowsはワークフローエンジンで、次の理由で採用しました。

テストをCIに組み込むのに、テストを任意のタイミングで実行できると便利だと思うのですが、Argo Eventsと組み合わせることで、20以上のイベントソースからワークフローを発火できます。今回はテストをワークフローに定義することとなり、これだけイベントソースに選択肢があればよきタイミングでテストを実行できそうです。
ただ後述しますが、現時点ではArgo WorkflowsのAPIをwebhookで直に叩いているので、Argo Eventsとはまだ組み合わせてません😢

  • テストとは関係なく通常の開発業務でワークフローエンジンとして利用し、Jobの実行順序をコントロールできること

過去に自分が作ったJobで実行順序が重要なJobで、CronJobの実行時刻の前後で制御しているものがあり、こういったJobをArgo Workflowsで制御できたら安心できます。技術負債ですがクリティカルに業務に関わってくる部分ではないので許されている感があります。

scenarigoはAPIサーバーのシナリオテストを書けるツールで、次の理由で採用しました。

  • テストシナリオをyamlでかけること
  • pluginを実装すれば拡張できて、多様なケースに対応できること

その他有名どころだと、newmanを採用することも考えましたが、JSONでテストがエクスポートされ可読性が低く、テストケースの管理が難しいという問題が指摘されていたため、採用を見送りました。

また、runnもyamlでかけるし魅力的でした。主観ですが、scenarigoとrunnを比べてみて、scenarigoの方がより直感的にテストをかけ、学習コストが低そうだと判断したので、scenarigoを採用しました。

全体の仕組み

前提として、弊社では各環境でのデプロイをArgo CDで行っています。こちらの弊社ブログの記事が詳しいです。また、開発環境でIntegration Testの仕組みを構築しており、テスト対象のマイクロサービスが依存するものはすべて開発環境上のものを利用します。
それでは、これらの技術をどのように組み合わせているのか、図示します。

Integration Test のシーケンス図

  1. 開発者がfeatureブランチで作業し、mainまたはdevelopmentブランチにPRを出してマージします
  2. GitHub Actionsが動き、マージされた内容でマイクローサービスのイメージ、テストのイメージを作成しECRにpushします
  3. Argo CDが、pushされたイメージを元にマイクロサービスをデプロイします
  4. デプロイ時に、InitコンテナでArgo Workflowsにwebhookして、デプロイされたことを通知します
  5. 通知を受け、Argo Workflowsはテスト対象のマイクロサービスと、それが依存するマイクロサービスを対象にhealthcheckを実行します
  6. healthcheckのレスポンスがすべてOKとなった場合、2でpushしたテストのイメージを使ってテストを実行します
  7. テストが完了したら、開発者に通知をだします。現在はslackで通知しています

テスト実行の様子はこのようにArgo Workflowsから確認できます。

Integration Test を実行している様子

また、テストのログもこういった形で確認できます。

Integration Test のログ

今後の展望

導入したばかりなのでまだまだやりたいことはたくさんあります。
現在はテストの結果を確認し、安全そうであれば手動で本番環境デプロイ用のPRをマージして本番環境反映というような形になっています。が、このテストがOKになるまでマージできない等の仕組みができれば、より安全に運用できます。あるいは、featureブランチをマージする前にテストが実行できて、それがOKになるまでマージできない、という仕組みがあればかなり理想的です。
また、テストケース自体も一部のマイクロサービスを対象にしか実装できていないので横展開していきたいです。

今後も、またテスト関連で記事を書くと思うので、経過なども共有できたらなと思います。
最後までお読みいただきありがとうございました。

GitHubで編集を提案
株式会社エスマット

Discussion