【クラウドネイティブ会議】外部連携を含む統合テストをどう自動化するか ~ステートフルモックとシナリオ駆動の実践~
外部サービスとの連携が前提のシステムでの統合テストに利用されるモックに、ステートフル性を持たせるという日立製作所の試みを解説したセッションを紹介する。
6:01
クラウドネイティブ会議に、日立製作所OSSソリューションセンタ企画員の蛭田哲大氏が登壇し、「CI/CD実現を見据えた統合テストの設計と実装 ~外部接続テストを自動化するモック活用の実践~」と題したセッションを行った。蛭田氏は、認証認可OSSであるKeycloakを用いたシステム構築や機能開発に従事しており、本セッションではその知見をもとに、認証認可サーバー開発をユースケースとした統合テスト自動化の取り組みを紹介した。
CI/CD時代に高まる統合テスト自動化の重要性
蛭田氏はまず、クラウドネイティブ開発におけるテストの位置づけから説明した。近年はアジャイル開発やDevOpsの普及により、変更に素早く追従するため、コード変更のたびにビルド、テスト、フィードバックを継続的に回す運用が前提となっている。コード変更を起点にビルドとテストが走り、リリースや運用で得られたフィードバックが次の変更につながる。このようなループでは、テストは一度だけ実行するものではなく、繰り返し自動実行できることが求められる。「このようなループでは、テストは一度だけ実行されるものではなく、繰り返し自動実行できることが求められます。つまり、CI/CDではテスト自動化が前提になります」と蛭田氏は語った。
中でも重要なのが統合テストである。テストには、関数単位で確認する単体テスト、複数の関数やモジュールを組み合わせて確認する結合テスト、そしてシステム全体としての振る舞いを検証する統合テストがある。統合テストは、外部システムとのインターフェースや、システム間の相互作用を確認する役割を持つ。システム全体の品質を担保するうえで、不可欠なテストなのである。
とくに近年のシステムは、複数の外部サービスと連携することが前提になっている。外部連携が増えれば、通信パターンや組み合わせは増大し、インターフェースも複雑になる。結果として、統合テストで検証すべき範囲は広がっていく。蛭田氏は、外部連携するシステムが多いほど、統合テストの重要性は高まると説明した。
一方で、外部システムを含む統合テストには実行上の難しさがある。外部システムの状態を自由に制御できなければ、同じ条件でテストを繰り返すことは難しい。テスト環境を占有できない場合は、スケジュール調整が必要になる。さらに、外部APIの利用制限や課金がある場合、CI/CDのたびに何度も実行すること自体が現実的でなくなる。こうした制約により、CI/CDで求められる「安定した継続実行」が阻害される。
既存モックでは再現できない認証認可フローの現実
こうした外部依存の問題に対して、一般的に採られるのが外部システムをモックに置き換えるアプローチである。モックを利用すれば、状態を任意に制御できるため、同一条件でテストを実行しやすい。テスト専用環境として利用できるため、外部環境の占有やスケジュール調整も不要になる。API制限や課金の影響も受けにくく、統合テストを繰り返し実行する手段として有効である。
しかし蛭田氏は、一般的なモックには限界があると指摘した。多くのモックサーバーは、リクエストを受け取り、定義済みのレスポンスを返すステートレスなRequest/Responseモデルで構成されている。この方式は単発の通信には対応しやすいが、リクエスト間で値を引き継ぐステートフルな通信や、複数ステップで進む通信を再現することは難しい。「単発の通信には対応できますが、ステートフルな通信や複数ステップの通信の再現は難しくなっています」と蛭田氏は語った。
具体例として示されたのが、認証認可システムにおける認可コードグラントのフローである。このフローでは、リソースサーバー、クライアント、ブラウザー、認可サーバーが関係する。ユーザーがブラウザーからサービスを要求すると、クライアントは認可サーバーへ認可リクエストを送り、認可サーバーはログイン画面を表示する。ユーザー認証が完了すると、認可サーバーからクライアントへ認可コードを含むコールバックが返る。クライアントはその認可コードを使ってトークンリクエストを送り、アクセストークンを取得する。さらに、そのアクセストークンを使ってリソースサーバーへアクセスし、リソースサーバーはトークン検証リクエストを認可サーバーへ送る。
この一連の処理では、認可コードやアクセストークンなどの値を複数のリクエスト間で引き継ぐ必要がある。つまり、状態を持たないモックでは正しく再現できない。また、認可サーバーからのコールバックを契機としてクライアントがトークンリクエストを送る、クライアントからのアクセスを契機としてリソースサーバーがトークン検証リクエストを送る、といった処理も発生する。モック自身がリクエストを送信できなければ、こうした複数ステップの通信も再現できない。
蛭田氏は、既存のモックの多くはステートレスであり、リクエストを受けてレスポンスを返すモデルにとどまると整理した。そのため、状態の引き継ぎやリクエスト送信を含む認証認可のようなフローでは、統合テストに必要な現実的な振る舞いを再現できないのである。
ステートフルモックとシナリオ駆動による解決策
こうした課題に対して、蛭田氏はモックをJavaで再設計した。アプローチの柱は「ステートフルモック」「リクエスト送信」そして「シナリオ駆動」の3つである。ステートフルモックでは、モック内部で状態を保持し、リクエスト間で値を引き継ぎながら状態遷移を再現する。リクエスト送信では、モック自身が外部にリクエストを送ることで、複数ステップの処理を再現する。そしてシナリオ駆動では、通信の流れをYAMLで定義し、柔軟性と保守性を両立させる。「ステートフルモック、リクエスト送信、シナリオ駆動という3つのアプローチで、モックをJavaで再設計しました」と蛭田氏は説明した。
蛭田氏は、従来のモックでは対応できなかったステートフルな通信、リクエスト送信、複数ステップの通信を、モック側の機能として実装したと説明した。これにより、認可コードやアクセストークンを引き継ぐ処理、コールバックを契機とした後続リクエスト、トークン検証のような多段の通信を、テスト環境内で再現できるようになる。
さらに特徴的なのが、YAMLによるシナリオ定義である。YAMLには、テスト対象となる通信の流れ、リクエスト内容、レスポンス、値の引き継ぎ、期待する結果などを記述する。コードにロジックを埋め込むのではなく、シナリオとして宣言的に定義することで、テスト内容を把握しやすくし、変更にも対応しやすくする狙いがある。
このYAML形式は、生成AIとの相性もよいと蛭田氏は説明した。構造的にフローを記述できるため、自然言語でテストしたいシナリオを入力し、YAMLやテストコードを生成する使い方がしやすい。本セッションの中心はモック設計だが、シナリオ駆動の設計によって、生成AIを活用したテストケース作成を高速化できる可能性も示された。
CI/CDへの組み込みを見据え、実行環境もDockerコンテナ化された。構成としては、モックのコンテナ、ブラウザーの実行環境コンテナ、テスト実行用コンテナ、テスト対象サーバーを用意する。Docker Composeを実行するだけで、統合テストに必要な一式が起動し、テストが実行される。環境差分を抑え、ワンコマンドで再現できる形にすることで、CI/CDパイプラインに載せやすくしている。
デモで示したシナリオ生成と統合テストの自動実行
最後に蛭田氏は、設計からCIでの実行までのデモを紹介した。デモは大きく2つである。1つ目は、生成AIを使ったテストシナリオとテストコードの生成だ。認証認可のシナリオを自然言語で入力し、モックサーバー設定のYAMLや、SelenideとJUnit 5によるテストコードを生成する流れが示された。
デモでは、OpenID Connect(OIDC)の認可コードフローを想定し、成功ケースと失敗ケースを含む認証認可シナリオが扱われた。具体的には、アクセストークンの取得からトークンイントロスペクション成功までを実行する成功ケースに加え、ユーザー名やパスワードの入力誤り、クライアント認証失敗といった失敗系のシナリオも用意された。蛭田氏は、生成AIを活用することで、自然言語の指示から数分でYAMLとテストコードを生成できることを示した。「一度プロンプトを確立してしまえば、シナリオの要件作成に注力でき、全体的な作成コストを下げることができます」と蛭田氏は語った。
2つ目は、Docker Composeによるワンコマンド実行のデモである。生成したファイルを実行環境に配置し、モック、ブラウザー実行環境、テスト実行環境、テスト対象サーバーをコンテナとして起動する。これにより、外部接続を含む統合テストを、ローカルやCI環境上でまとめて実行できる。デモでは、成功ケースと失敗ケースを含むテストが実行され、期待した結果が得られることが確認された。
最後に蛭田氏は、統合テストは設計次第でCI/CDに載せられるとまとめた。外部連携を含む統合テストでは、状態依存処理と、リクエスト送信を伴う複数ステップ処理の再現が必要となる。しかし、既存モックの多くはRequest/Responseモデルにとどまり、これらの振る舞いを再現する機能が不足している。そこで、ステートフルかつリクエスト送信可能なモックをシナリオ駆動で設計することで、認証認可のような実システムに近い統合テストの自動化を実現したのである。「統合テストは設計次第で、CI/CDに載せることができます」と蛭田氏は語った。蛭田氏のセッションは、モックを単なる外部システムの代替物ではなく、複雑な外部連携を再現するテスト基盤として設計する重要性を示すものだった。
- この記事のキーワード
この記事をシェアしてください
