オブジェクトの広場はオージス総研グループのエンジニアによる技術発表サイトです

マイクロサービス

マイクロサービスアーキテクチャに効く!テスト技法

マイクロサービスアーキテクチャならではのテスト観点と課題
オージス総研 技術部 アドバンストテクノロジセンター
今村 大輔
2022年4月21日

前回はサービス間インターフェースのテスト技法「CDCテスト」をご紹介しました。今回はマイクロサービスアーキテクチャならではのテスト観点と課題を全般的に考察・リストアップしたいと思います。

はじめに

皆さんは

  • テストケース作成タスクを引き受けたものの、何をテストすればよいかわからない
  • テスト実施タスクを割り振られたものの、どうやって動かせばよいか不明

などで困った経験はないでしょうか。テストと言うと、何となく新人さんが担当する比較的難易度の低いタスクという印象があるかもしれません。ですが、ホワイトボックステスト/ブラックボックステストを問わず、テスト対象の入出力が「どうなっていないといけないか」を正しく把握して挙動を観察するタスクです。テスト対象の「わかりやすさ」で難易度が大きく変動します。

マイクロサービスアーキテクチャのテストはとても難しいです。外部依存の要素が多数出てくるため、テスト対象を把握するのにそれなりの知識・経験が必要です。テスト対象を把握できないと、前述のような困りごとに直面して手が止まってしまいます。ましてや、実装した後にテストが難しいことに気づいても後の祭りです。

というわけで、今回は具体的なテスト技法はいったん脇に置いて、マイクロサービスアーキテクチャにおけるテストの全体像を考察します。「とても難しい」というモヤモヤした「問題」を具体的にブレイクダウンして、解決策を検討できる「課題」として抽出してみたいと思います。

そのために、まずは「システム全体でどのように品質が担保されるのか」というテスト戦略をイメージし、その戦略から「何をテストするのか」というテスト観点を洗い出してみましょう。テスト観点の単位までブレイクダウンできれば、「どうやってテスト実施するか」という「課題」として扱うことができます。解決策となるテスト技法の検討にステップを進められます。

そして、テスト観点とその課題から逆算して設計を実施し、テスト技法を整備して、人海戦術に頼らず地道に自動化を積み重ねることで、品質やテストの労力が変わってくるはずです。

マイクロサービスアーキテクチャのテスト戦略

では、マイクロサービスアーキテクチャにおけるテスト戦略とは、どのようなものでしょうか。プロジェクトのシチュエーション(対象業務領域、分割境界設計、要素技術、工数、その他諸々)によって最適なテスト戦略は異なるでしょう。その上、時間軸で生き物のように変化し続けるマイクロサービス群に対峙して、テスト戦略も変化させていかなければなりません。

この問いに明解な答えはありませんが、立脚すべき原則として以下が考えられるのではないでしょうか。

  • 基本はいつものV字モデル
  • マイクロサービスならではの結合ポイントを見つける
  • 役割分担が変化する点に注意

それぞれについて、詳しく説明します。

基本はいつものV字モデル

この記事の読者であれば、V字モデルはよくご存じでしょう。個々の工程名称や粒度、実施事項はさておき、要件を小さな部品にブレイクダウンして設計し、対になる形で部品単体→組み合わせ→全体で品質を検証する考え方です。ビッグバンでいきなり全体を組み合わせると、あちこちにバグがあるため動かすことすらままなりません。それを回避するため、部品を段階的に結合してテストします。

ウォーターフォール型のやり方のように見えるかもしれませんが、マイクロサービスアーキテクチャとセットで採用されるであろうアジャイル型でも有用です。スプリント毎に小さなV字を繰り返すものと考えてください。各スプリントでxUnitによるクラス単位のテストから業務シナリオ単位のテストまでを段階的に実施します。

当然のことながら、スプリントを繰り返すのでテストの自動化が必要になります。いきなり全てを自動化するのは不可能なので、TDDのドライバとして部品単体レベルのテストを実装しながら、QAの仕組みとして組み合わせ・全体の自動テストを継続的に整備・発展させていくことになるでしょう。

マイクロサービスならではの結合ポイントを見つける

モノリスからマイクロサービスアーキテクチャへ進化させるにあたり、結合試験が大変になるのは容易に想像できるところです。業務ドメイン毎のマイクロサービスが切り出され、互いに通信するようになれば結合するインターフェースが増加します。さらに、そのインターフェースの接続方式は様々です。シンプルなREST APIを基本として、非同期メッセージングやオブジェクトストレージのイベントなど、多種多様な方式が考えられます。

そして、マイクロサービスアーキテクチャではモノリスの頃は存在しなかった新たなインターフェースが出現することに注意してください。

わかりやすい例が「共通部品」です。これまでは明確に品質保証上の結合ポイントとして挙げだすことは少なかったのではと思います。マイクロサービスアーキテクチャにおいては、このあたりも結合ポイントになります。

モノリス/ウォーターフォールの頃、共通部品はフレームワークなどプロジェクト全体の中核になるライブラリでした。明確な結合試験を実施するというよりは、およそ業務機能の実装の中で叩かれて「品質上問題ない」と判断されていたと思います。そして、プロジェクト全体が結合テストを迎えるころには共通部品チームは縮小/解散していたものと思います。その成果物は固定され、よほどのことが無ければ改修されないものでした。

それが、マイクロサービスアーキテクチャ/アジャイルの枠組みでは、共通部品はサイドカーや共通サービスとして切り出されます。機能的にも、フレームワークのような中核機能ではなくなります。ログのルーティングやサービスメッシュなど、業務のドメインサービスからネットワーク等を介して利用するもので、インターフェースが発生します。そして、業務と並行して継続的にエンハンス開発が続きます。つまり、継続的な回帰テストが必要になります。

設計・実装に関与していないPMOのテスト推進担当者が結合テストを旗振りする場合など、気づきにくいポイントでしょう。このような箇所を見落とさず、依存関係を紐解いて段取りを計画することがスムーズに試験を進行させる勘所です。

役割分担が変化する点に注意

マイクロサービスのテスト設計にあたり、注意を要するポイントがチーム間の役割分担です。役割分担の変化に伴い、品質管理責任のスコープも変わります。その過程でテストの担当があやふやになり、テスト観点の抜け・漏れが発生するリスクがあります。

では、どのようにチームとその役割分担が変化するのでしょうか。これまでは大別して「アプリケーション開発」と「インフラ構築・運用」で別組織をとるケースが大多数でした。それが、マイクロサービスアーキテクチャを推進しているメガベンチャーの動向から読み取るに、これからはアプリケーション技術者とインフラ技術者が混交したサービス単位・多数の開発チームとシステム全体の信頼性向上を担うSREチームに収斂していくと思われます。

サービス単位・多数の開発チームとSREチームのテストにおける役割分担というだけでも具体的な共通認識は持ち難いと思います。さらに言うならば、この組織形態は(一旦の)最終形です。前段落で「収斂」という言葉を使用しましたが、そこに落ち着くまでには曲折紆余あることが予想されます。チームの集合離散に同期してテストの役割分担も常に見直し続けなければなりません。そして、テストの役割分担が変動してもスムーズな引き継ぎができるように、ノウハウ・テストケース・自動テストの実装を蓄積・流通できるようにしたいところです。

テスト観点抽出のフレームワーク

上記のテスト戦略を基に、具体的にマイクロサービスアーキテクチャならではのテスト観点を抽出してみましょう。

テスト観点の抽出にあたり、非常に有名なフレームワークがあります。「アジャイルテストの4象限」です。

アジャイルテストの4象限

上図の通り、

  • 横軸に「プログラミングのサポート」<−>「製品の批評」
  • 縦軸に「ビジネス側」<−>「技術側」

をとる4象限のマトリクスです。

テスト対象に対し、それぞれのカテゴリから必要なテストを洗い出す形で使用します。縦・横の軸が象徴するように、特定の立場(「プログラマ」「QAエンジニア」「企画担当」とか)に偏らず、広い視野でテスト観点を洗い出せるのが特徴です。

このフレームワーク自体は、Brian Marickによって2003年にXP(エクストリーム・プログラミング)の文脈で提唱されたものです。やや古く感じるかもしれませんが、2022年現在でも通用する普遍的な枠組みではないでしょうか。マイクロサービスアーキテクチャのバイブルであるSam Newman『マイクロサービスアーキテクチャ』、Chris Richardson『マイクロサービスパターン』の両書でも同フレームワークを引用する形でマイクロサービスアーキテクチャとテスト戦略が論じられています。

このフレームワークを通じて、マイクロサービスアーキテクチャのシステムは各象限で

  • どのようなテスト観点が必要か
  • そのテスト観点はモノリスの頃からどう変化するか
  • そのテスト観点の重要度・優先度はどれほどか
  • そのテスト観点を担保するにはどのようなテスト技法が必要か
  • テスト技法の実施にあたり何が課題になるのか

といったことについて、考察したいと思います。

第一象限 プログラミングのサポート/技術側 のテスト観点

ソフトウェアテストの基礎となる象限です。開発者自身が主導し、システムの内部品質を担保するテスト観点です。マイクロサービスアーキテクチャの文脈では、以下のようなテストだと考えるとよいでしょう。

  • サービスの機能要求に対するテスト
  • サービス単体に閉じたもの

Janet Gregory・Lisa Crispin『実践アジャイルテスト テスターとアジャイルチームのための実践ガイド』ではクラス間のインタラクションをテストする「コンポーネントテスト」もこの象限に位置付けられています。いわゆる詳細設計に対応するテストの「単体テスト」よりは、もう少し広い概念と解釈できます。

この象限で必要になるテスト観点として、以下が考えられます。

  • クラスの振舞い
  • 画面の振舞い
  • サービスのインターフェース
  • サービスの振舞い
  • インフラの振舞い
  • 共通サイドカーの振舞い

それぞれについて、詳しく考察してみましょう。

クラスの振舞い

改めて説明するまでもない、お馴染みのテストです。サービスを構成するクラスに対し、xUnit等でその振舞いが期待通りであるかを検証するテスト観点です。実装するテストコードはTDDのテスティングペアとして利用します。ノウハウとしては十分に成熟したテスト観点と言えるでしょう。

マイクロサービスアーキテクチャにおいては、個々のサービスが従来よりも小規模で独立したものになります。クラス単位ではなくサービス単位でも十分にテスタブルかもしれません。従来と比べて重要度は下がるのではないでしょうか。

UIの振舞い

こちらも従来からある、お馴染みのテストです。UI項目とその振舞いが期待通りであるかを検証するテスト観点です。SeleniumやCypress等の自動化ツールも成熟してはいますが、人手による打鍵実施も根強く定着しています。

文献によっては、UIのテスト自動化、ひいては「UIを起点にDBまで貫通して動作させるテスト」という意味で、このテスト観点をE2Eテストと呼んでいますが、本記事ではもっとUIに特化した詳細なテストをイメージしています。マイクロサービスアーキテクチャの文脈においては、複数サービスを横断して実施するテストをE2Eテストと呼び、単に「UIが起点」というものとは区別するべきでしょう。テスト戦略の「基本はいつものV字モデル」で述べた通り、全体を組み合わせるE2Eテストの前段として、UI単体に閉じた範囲でバグを摘み取っておくのが良いと思います。

テストに閉じない、設計にも踏み込んだ問題提起になりますが、システム全体としてテスタビリティをどのように高めるかがマイクロサービスアーキテクチャにおける本テスト観点の課題です。画面個別の要件に引きずられてバックエンドのAPIを複雑化させないようにし、UIを切り出して自動回帰テストでデグレードを検知しましょう。そして、仕上げとして人手の打鍵でファジィな課題を洗い出すのが理想です。

マイクロサービスアーキテクチャに限りませんが、システムのUIとサービスのインターフェースが複雑化する要因として、UIがアクター毎に個別最適化される点が挙げられます。例えば、宅配便で「再配達を依頼する」というユースケースであれば、

  • コンシューマ
    • スマホアプリ
    • iOS
    • Android
    • ブラウザ(SPA)
    • 電話(自動応答受付)
  • コールセンター
    • Salesforce
  • 社内管理者
    • ブラウザ(基幹システムの画面)

・・・といったUIが想定できるでしょう。それぞれに求められるデータ項目や非機能特性はかなり異なるものです。マイクロサービスアーキテクチャとしては「配達サービス」が提供する汎用のAPIで各UIを実現したいところですが、そう簡単にはいきません。個々のUI毎に付帯するデータ項目などが出てきます。そのデータ項目に対するCRUDを「配達サービス」側で対応するとドメインの独立性が失われ、社内管理者向けのエンハンスがコンシューマのトラブルを引き起こすといったリスクが高まります。逆に、クライアント側で個別にその他のサービスと組み合わせると、依存先サービスが増加してUIを単独で切り出して動かすのが難しくなります。テスタビリティが大幅に下がります。

このような課題に対応するデザインパターンとして、Backends For Frontends(BFF)が提唱されています。各UIと1:1で対応づく専用のサービスを配置し、そのサービスでUI個別のデータ項目や非機能特性に対応してUIとバックエンドサービス双方の複雑さを吸収する設計手法です。専用でサービスを追加することになるため、ぱっと見は複雑性が高まっているように見えるかもしれません。ですが、UIはBFFのサービスとだけ通信するためテスタビリティが高まり、バックエンドサービスはドメインの独立性を維持できます。

各UIの開発者がサーバサイドのサービスも構築・運用できるという条件付きではありますが、是非、早期に適用検討したい設計パターンです。詳しく知りたい方は、Microsoftが公開しているクラウド設計パターンの記事が参考になるでしょう。

サービスのインターフェース

サービス間のインターフェースが合致していることを検証するテスト観点です。

第1回に記載したことの再掲になりますが、単純にサービスを分割すればするほどインターフェースの数が増えます。多数のサービスが同時並行でエンハンス開発され続けると、最新インターフェース仕様への追従や下位互換を保つための作業が雪ダルマ式に膨張します。 また、サービス間を実際に結合して試験するためには、互いに実装がある程度成熟している必要があります。よって、試験できるのはプロジェクトの終盤戦。問題を検出することができても、本質的対応は取れない場合が多いでしょう。

このような課題を解決するのがCDCテスト(Consumer Driven Contract Testing)で、以下のコンセプトに基づいたテスト技法です。

  • サービス間連携のインターフェースをTDDするテスト技法です
  • コンシューマ主導で作成される「Contract」と呼ばれる入出力データの定義からコンシューマ/プロデューサのスタブとテストコードを自動生成します
  • プロデューサは「Contract」を元にCI(自動回帰試験)することで、都度の変更がコンシューマに影響しないことを判断・保証します。コンシューマもまた同様です
  • 「Contract」はコンシューマ/プロデューサで共有します。GitHub等で管理し、Pull Requestで仕様変更を通知・記録します

CDCテストの詳細について、第1回~第3回で詳しく解説しています。興味があれば是非ご覧ください。

サービスの振舞い

この観点も改めて説明する必要はないでしょう。従来のアプリケーションの内部結合試験と同様の観点です。各サービスのインターフェースに対し、xUnitからネットワーク越しに入力を与え、出力内容を検証します。ノウハウとしては十分に成熟したテスト観点と言えるでしょう。サービスの規模をコンパクトに維持できていれば、前述したCDCテスト(Consumer Driven Contract Testing)と合わせて試験しても良いかもしれません。

インフラの振舞い

マイクロサービスアーキテクチャの場合、インフラもIaC(Infrastructure as Code)のソフトウェアとして制御されている場合が大多数でしょう。そして、アプリケーション同様、スプリント毎に新たなfeatureが追加されて変化し続けます。つまり、テストの自動化によるデグレード検知が必要ということです。

テストの視点でIaCを考察すると、総じて「テストのし難さ」が課題のように感じます。以下の点でテスタビリティが高まらず、網の目が大きいE2Eテスト(アプリケーションの動作確認を兼ねたもの)で足元のリリースが成功したかを判定する場合が多いです。

  • デプロイしないと動かない
  • Immutableとは限らない
  • テストコードが書けるインフラエンジニアが希少

まず、デプロイしないと動かない点について。アプリケーションの場合、xUnitでクラス単位に開発PC上で動作させることができますが、IaCの場合はクラウド上に実際のインフラを構築して動作させることになります。テスト実行にあたり、それなりに時間がかかります。さらに、(実装方式にもよりますが)モジュールの単位が大きく、細かいテストが実施し難いです。

次に、Immutableとは限らない点について。IaCの考え方が出てきた頃、IaCとセットで語られる設計原則としてImmutable Infrastructureが提唱されていました。デプロイしたインフラには設定変更を実施することなく使い捨てる、設定変更を施したインフラをイチから自動でデプロイしなおす、という考え方です。ステートレスなのでテストとしてはシンプルでわかりやすいです。事後条件だけ考えればテストケースを作成できます。

この考え方は2022年現在でも有効です。その一方で、Mutable(ステートフル)なものとしてインフラを扱うIaCツールも増えています。宣言型でインフラ構成を定義し、実行時点のステートから差分更新の積み重ねで宣言した内容を構築する方式です。AWSのCloudformationであればupdate-stackコマンドがそれに当たりますし、Terraformであればtfstateファイルに実行結果を記録して更新時に参照しています。MutableなIaCツールを使用していても、環境を2系統用意の上、Blue-Green DeploymentしてImmutableになるよう扱うことも考えられますが、それも完全ではありません。データストアのストレージなど両系統の環境で共用してMutableに扱わなければならないリソースもほぼ確実に出てきます。

つまり、テストとしては事前条件に「状態がどうなっているか」を含めてテストケースを作成しなければならず、実施時には状態を再現する手間をかける必要があります。また、更新時にはインフラリソースの種別・変更内容毎に、純粋に設定更新するパターンや置換(新リソース作成と旧リソース削除)するパターンが混在しています。無停止デプロイが要件の場合、事後条件だけでなく、事中条件にも気を配る必要があります。

最後に、テストコードが書けるインフラエンジニアが希少である点について。これはシンプルな話で、まだまだインフラエンジニアがテスト自動化を実践・習得する必然性を感じるところまでニーズが成熟していないものと見ています。

クラウドサービスを利用していても、コンソールからの都度手作業で事足りる要件であるとか、ウォーターフォール型で繰り返し作業を想定していないプロセスが現状多数なのでしょう。オンプレの社内システムをリフト&シフトでクラウド移行する場合、リフト段階でIaCを実践する必然性は高くはありません。せいぜい、ステージング環境と本番環境で設定値を合わせるくらいの用途でしょうか。

また、ServerSpecやTerratestといったインフラ向けのxUnit相当のツールは存在するのですが、RubyやGoなどのプログラミング言語にOSSのライブラリを組み合わせてテストを実装するものです。インフラエンジニアが手慣れたシェルスクリプトやDOSバッチとは別パラダイムであることから、習得に向けたハードルがあるでしょう。実践の見込みがなければ、学習のモチベーションを上げずらいところです。

とは言え、オンプレのインフラをそのままクラウドに移行しても、必ずしもコスト効率が良いわけではないのはご存じの通りです。そう遠くない将来、リフト&シフトのリフト需要がひと段落し、シフト需要に移り変わっていくことが予想されます。シフトにあたり、継続的にクラウド最適化を図る取り組みになれば、テストコードを実装してインフラを自動テストする機運が高まるかもしれません。

サイドカーの振舞い

マイクロサービスアーキテクチャならではの新たなテストです。各サービスとペアになって配備されるサイドカーの振舞いが期待通りであるかを検証するテスト観点です。

従来、「共通部品」と呼ばれていた機能群について、ライブラリ提供されて各アプリケーションが取り込む形態が一般的でした。それがマイクロサービスアーキテクチャになると、共通サービスやサイドカーとして切り出されます。中でも特に、サービスメッシュやログ管理、ビジネスルール管理などがサイドカーで提供されることが多いです。開発プロセスの上ではサービス本体と並行して開発され、結合試験で実際に組み合わせる流れになります。すなわち、モノリスからテスト戦略が顕著に変化するポイントです。

サイドカーならではのテストの課題は、(共通サービスとして独立させるのと比べて)サービス本体との結合が密結合になる点です。多くのケースでサービス本体とサイドカーはノードやストレージ領域など物理リソースを共有しているものと思います。これらサービス本体との結合ポイントを適切に仕様化し、スタブやテストデータを適切に構成しなければなりません。試験そのものと言うよりは、試験のお膳立てとその維持管理が課題でしょう。

第二象限 プログラミングのサポート/ビジネス側 のテスト観点

システム全体として、機能要求が満たされていることを検証するテストの象限です。ビジネス担当者、或いは、その代行でQAエンジニア(QAチーム)が実施し、このテストのPASSをもってリリース可とする場合が多いでしょう。

この象限で必要になるテスト観点として、以下が考えられます。

  • データが起点業務から終点業務まで正しく流れるか
  • 入出力が現行システム/新システムで合致するか

それぞれについて、詳しく考察してみましょう。

データが起点業務から終点業務まで正しく流れるか

改めて説明するまでもない、業務シナリオベースのサービス間結合です。E2Eテストと呼ばれています。UI操作などをトリガとして、関連する全てのサービスが期待通りに協調連携し、データが整合することを検証します。品質保証における最後の砦であり、最重要テスト観点であると言い切って差し支えないでしょう。

マイクロサービスアーキテクチャに限った話ではありませんが、E2Eテストの自動化は非常に困難だと言われています。一般によく言われる課題だと、

  • メンテナンスが大変
  • 実行に時間がかかる

などでしょう。

まず、「メンテナンスが大変」という課題についてです。当然のことですが、E2Eテストの実装もシステムと密接に結合します。システムの更改に継続的に追従しなければなりません。さまざまなE2Eテストツールがメンテナンス性の良さを競っていますが、そもそものところでテスト実装のメンテナンスから逃げることはできないです。複数サービスを横断するE2Eテストをメンテナンスする場合、全体に目を光らせて、いつ・どのサービスが・どのように更改されるのかをウォッチするだけでも相当な労力がかかります。

また、一般的なE2Eテストのツールが主対象とするものはUIである場合が多いです。ですが、業務シナリオベースのサービス間結合としては、データストアやQueueに蓄積された処理結果のデータまで確認したいところ。UIのキャプチャ&リプレイツールだけでは充足しない可能性が高いです。初期データの仕込みから出力データとの期待値比較まで、xUnitのテストコードとして壮大な手続きを実装することになります。

次に、「実行に時間がかかる」について。当たり前の話ではありますが、業務シナリオに沿って、ひとつひとつ機能を操作し、データストア上のデータをダンプして期待値との突合を行うため、かなりの所要時間がかかります。

筆者が経験したあるプロジェクトでは、IaCによるインフラのデプロイからE2Eの業務テスト完了までおよそ数時間でした。ナイトリービルドでデグレードを検出するのにちょうどよい所要時間でしたし、実装に手を入れる時の安心感がまるで違いました。とは言え、所要時間はある種偶然の結果です。パラメータの網羅や細部のデータまでテストしだすと朝までに終わらなかったでしょう。テストを並列実行して時間短縮を図ることも考えられますが、テストデータが競合しないよう分離する、或いは、複数面の試験環境構築など、とてつもなく複雑化します。そのプロジェクトのリソースでは非現実的な打ち手でした。

これら課題に対する解決策ですが、リリース前の最終確認として割り切ってしまうのが現実的でしょう。テストケースとなる業務シナリオを「壊れているとビジネスが成立しない」ものに絞り込んで実装・維持管理するのが良いとされています。絞り込みの切り口としては、金銭のやりとりが発生する「マネーパス」が有名です。絞り込みによって漏れてしまう業務シナリオは第一象限の各テストの組み合わせで論理的に担保できるよう、テスト仕様をサービス横断でレビューするなどの対策が考えられます。

入出力が現行システム/新システムで合致するか

業務内容はそのままに、新たなアーキテクチャでシステムをリプレイスするプロジェクトで頻出するテスト観点です。入力に対して稼働中の現行システムと開発中の新システムで出力されるデータが合致していることを確認します。しばしば現新比較テストと呼ばれます。地味な観点ではありますが、意外とプライオリティが高いテストです。

このテスト観点の中でも特に、結果整合性の扱いがマイクロサービスアーキテクチャならではの課題ポイントです。旧システムがモノリスで単独のRDBであった場合、そもそも「結果整合」という発想が無いと思います。新システムではデータが分散配置となり非同期で更新されることから、タイミング次第では旧システムと新システムで出力内容が相違します。実際のところ不整合なのは一瞬の場合がほとんどですが、一部の内部的なサービスを停止しつつ、システム全体としては継続稼働している状態など、ある程度の期間不整合が発生する場合もあり得ます。

つまり、従来は旧システムと新システムの画面を比較してOK/NGを判断していたところを、(業務に照らして、意味合い上)許容できるデータ不整合であるかまで考えてOK/NGを判定しなければなりません。

第三象限 製品の批評/ビジネス側 のテスト観点

システムの改良・エンハンスを目的として新たな要求を発見する/仮説を検証するテストの象限です。システムが仕様通りの振舞いをするかの評価ではなく、システムに何が足りていないかを洗い出して新たな要求を獲得するためのテスト観点です。

この象限で必要になるテスト観点として、以下が考えられます。

  • 障害対応訓練
  • 新機能の限定開放/効果測定比較

それぞれについて、詳しく考察してみましょう。

障害対応訓練

いわゆるカオスエンジニアリングです。本番環境で意図的に障害を発生させ、部分的問題はありつつも、システム全体としてはサービスを継続提供できるかを検証します。ビジネス視点でBCP(事業継続計画)やDR(災害復旧計画)の課題を、技術視点で異常系例外処理や可観測性の課題を炙り出します。

障害を注入するツールがOSSやマネージドサービスで次々にローンチされてHotな領域ではありますが、テスト観点としてのプライオリティは必ずしも高くないのでは?とも思います。マイクロサービスアーキテクチャを立ち上げた当初であれば、きっとサービスの数は3つ~4つ程度。ギリギリのところでシステムの全体像を把握した各サービスの中核開発者による属人対応で対処できるのではないでしょうか。

リスクを取ってでもカオスエンジニアリングを実施する必要があり、なおかつ、実際に行えるのは

  • サービス数増加や人材の新陳代謝でシステムの全体像を把握している開発者がいない
  • システム規模拡大に伴い開発と運用で組織が分化傾向にある、距離感がある
  • CTO/CIOクラスの役職者が音頭を取り、責任を引き受けられる
  • 現実の障害をそれなりに経験・対処しており、経営にインパクトがない範疇のダメージで済む確信がある

といった状況でしょう。システムとして相応に成熟した状態であると思います。ここまで到達するには、テストも含めて様々な課題を乗り越えてビジネスを成長させなければなりません。より高いプライオリティのテスト観点を先行して解決する必要があるでしょう。

その一方で、カオスエンジニアリングの重要性は確実に認知されつつあります。ある金融機関で発生した障害において、分散システムとしてのエラーハンドリングが機能せず、システム全体のダウンにつながりました。原因・経緯の中で「取引サービス禁止機能における作動条件の緩和」を行った結果、「多くの処理区画が短時間に閉塞されてATMに係る顧客影響が急激に拡大した」ことが調査報告書で公表されています。まさしく、サービスメッシュにおけるトラフィック管理・サーキットブレーカ運用の話です。そして、再発防止策として「障害時訓練等の高度化」を検討するとされています。この策がすなわちカオスエンジニアリングというわけではないと思いますが、実地訓練は有効な手立てでしょう。プレッシャーのかかる状況下、集団で的確な判断・アクションが取れるようになるには経験学習の蓄積が必要です。

今後、(マイクロサービスアーキテクチャと言うよりは)分散システムとしてカオスエンジニアリングを計画~実施~課題形成するコンサルティング需要が高まる予感がします。

新機能の限定開放/効果測定比較

ECサイトや広告プラットフォームなどでよく実施されるテストです。UIを中心とした新機能を一部のユーザにのみ公開し、クリック数や成約件数といったメトリクスを新旧比較することで、望ましい効果を得られるか・得られないなら何が課題なのかを明らかにします。一般に、A/Bテストと呼ばれています。

開発者の立場からすると、テストというよりも

  • ログ出力内容と可視化
  • 機能配置と振り分けルール
  • デプロイ

をどのように設計・実装するかが課題でしょう。事実上、テストのマイクロサービスを新たに追加するくらいボリューム感あるタスクではないでしょうか。

第四象限 製品の批評/技術側 のテスト観点

技術面からシステムの課題を発見するテストの象限です。総じて、非機能面のテストやサービス(開発チーム)を横断する技術的専門性の高いテスト観点がカテゴライズされます。

この象限で必要になるテスト観点として、以下が考えられます。

  • 性能要求が充足しているか
  • 処理量に応じてスケールイン/アウト(ダウン/アップ)し、目標時間内に処理が完了するか
  • 脆弱性が無いか
  • 複数サービスが協調連携し、意図した通りのトランザクションになること
  • Pod/Taskの振舞い

それぞれについて、詳しく考察してみましょう。

性能要求が充足しているか

時間あたりのトランザクション数や平均レスポンス時間などが目標値をクリアしていることを検証します。主に、オンライン処理が快適に利用できるかが焦点です。マイクロサービスアーキテクチャにおいては、UIと密接に結合するAPIやスケールアウトによる性能向上が見込めないサービスが主対象になります。

マイクロサービスアーキテクチャならではの性能問題でありがちなのが、サービス間連携で同期通信をシリアル実行しているため処理に時間がかかる問題です。例えば、サービスがA → (HTTP) → B → (HTTP) → C → (HTTP) → Dのように数珠つなぎされていると、トータルの処理時間は各HTTP通信にかかる時間の総和以上。UIだと利用者がストレスを感じるレベルでしょう。

さらに、マイクロサービスアーキテクチャの場合、利用する/される先のサービスもそれぞれ継続的に変化し続けます。サービスAがサービスBを同期接続していたとして、サービスAがある時点で性能要求を充足していたとしても、ある日、サービスBがサービスCを同期接続するようになれば、それに引っ張られてサービスAが性能要求を充足できなくなることも考えられます。

これら課題について、テスト工程やその技法に閉じたところでは解決しきれません。性能要求に満たない場合、従来のモノリスではミドルウェアのパラメータやデータアクセスの仕方をチューニングすることで対応していました。マイクロサービスアーキテクチャでは非同期メッセージングでの連携や処理のパラレル実行など根本的な設計に立ち返らないと対応できない可能性があります。さらに、依存するサービスの変化を継続的にモニタリングする必要が出てきます。

そこで、キーワードになるのが「オブザーバビリティ(可観測性)」です。テストやQAではなく運用における方法論で、システム内部状態の観察だと捉えてください。サービス間通信のトレースや各種メトリクス、ログ出力などから、稼働状況を可視化します。この内容を全サービスの開発者同士で共有し、システムとして最適化を図っていくことになります。

処理量に応じてスケールイン/アウト(ダウン/アップ)し、目標時間内に処理が完了するか

スケーラビリティの妥当性を担保する試験です。スケールして「正常動作するか」の単純検証もありますが、本質的にはこのテスト観点を通じてクラウド資源の利用コスト最適化を図ることになります。オンライン処理にも必要な観点ですが、バッチ処理や準リアルタイム処理が主になるでしょう。

けっこう難易度の高いテスト観点です。クラウド資源の使用量とコストを可視化するサービスは様々なベンダーによって提供されていますが、どのような用途・要件で利用しているのか把握して「最適であるか」を判断してもらえるわけではありません。開発側(クラウドサービスを利用する側)が主体となってムダを発見し、最適なスケールのさせ方(イベント発火条件やインスタンスの多重度)を設計する必要があります。本格的にやるなら、数理計画法の知識が必要になるでしょう。

では、どうやってムダの発見と最適なスケールのさせ方を設計するかという話なのですが、特効の技法があるわけではありません。当たり前すぎるかもしれませんが、ログ収集と実験を地道に繰り返すことになります。メトリクスとなる要素を洗い出してログ出力し、パラメータを少しづつ変えて実行し、その結果をグラフにプロットして、コストとパラメータの関係を明らかにします。

また、このテスト観点の対応優先度は決して低くはないと思います。例えば、ドル建て支払のパブリッククラウドを利用していて、為替レートが円安に振れた場合など、早急なコスト削減が必要なビジネス局面はあり得ます。いざ削減しようにも、どこにムダがあるかが不明で、ログの仕込みから手をつけているようだと、初動が遅れて傷口を広げることになりかねません。実際に対応するかはともかく、このテスト観点を通じて対応候補箇所を洗い出しておくことに意義はあるでしょう。

そして、このテスト観点に関連する話題として、海外ではFinOpsと呼ばれる方法論が話題になりつつあります。「Ops」という接尾語から容易に想像できると思いますが、財務の観点からパブリッククラウド利用コストを継続的に最適化する取り組みです。「テスト」の切り口とは異なりますが、目指すところは近いです。この先、FinOpsを具体化したテスト手段やツールが生まれてくるかもしれません。要注目です。

脆弱性が無いか

いわゆる脆弱性検査やペネトレーションテストです。セキュリティにまつわるテストはかなり広範なのですが、ここでは外部から疑似攻撃を仕掛けて脆弱性を検出する試験と考えてください。個々のサービスに閉じて実施する事項も多く、もしかすると単体テストにカテゴライズするほうが良いかもしれません。ですが、攻撃手法・クラッキングツールに精通した専門技術者が第三者の立場で実施する場合が多いのと、検査の定期実施が必要なことから、本記事では第四象限のテストとして位置付けています。

マイクロサービスアーキテクチャならではの脆弱性検査の課題として認識しなければならないのが、

  • サービス毎に実装方式・成熟度が大きく異なる
  • サービス間の接続方式が多様である

あたりでしょう。

まず、サービス毎に実装方式・成熟度が大きく異なる点について。従来のモノリスであれば、単一の基盤上に標準化された設計・実装のアプリケーションが配備されているケースが多かったと思います。その基盤・標準が適切に脆弱性管理されていれば、スクリプトキディのイタズラ程度ではビクともしない程度に問題を打ち取れていたでしょう。

それに対し、サービス毎にインフラ・ミドルウェア・実装言語が異なるマイクロサービスアーキテクチャにおいては、サービス個別に脆弱性の検査・管理を行う必要があります。セキュリティチームのような有識の共通専門スタッフを配置していても、個別実装レベルになると手出しできません。チェックリストによる監査で統制する形になりそうです。各サービスを開発する立場としても、回帰テストの自動化が追いついていない状況では脆弱性が公表されたOSSライブラリのバージョンアップすらままなりません。

次に、サービス間の接続方式が多様であることについてです。脆弱性検査は専用ツールを利用して実施するのが一般的ですが、サービス間の接続方式によってはテスト不可能かもしれません。アプリケーションの診断ツールはHTTP/1.xのみの対応であることが多いです。gRPC、その他非同期メッセージングなど、特殊なプロトコルによるサービス間接続の場合、(2022年現在は)事実上診断不可能でしょう。

これに関しては本質的な解決手段はありません。ツールをあきらめて手作業で怪しいパラメータのパターン網羅を試みるのはさすがに無理があります。現実的には、脆弱性検査対象をインターネットに公開するAPIに限定するよう要求仕様化し、設計段階で脆弱性検査できる接続方式を選定する形に落とし込まなければなりません。事実上、RESTのWeb API一択です。試験対象がセンシティヴなデータを扱うサービスであれば、インターナルなサービスでも脆弱性検査を求められることも考えられます。接続方式検討上の制約になり得るため、注意が必要です。

複数サービスが協調連携し、意図した通りのトランザクションになること

システム全体としてCRUDの妥当性を検証するテストです。DOA(データ中心アプローチ)でシステム設計する場合、CRUD分析を通じてデータのライフサイクルと業務プロセスが整合するかを検証し、テスト工程では機能間結合の組み合わせパターン抽出を実施しているかと思います。

モノリスの頃は比較的あっさりしたテストで済んでいたかもしれません。データが単独のRDBに集約されているため、CRUD図をもとに各機能を実行すれば機能間の認識相違による不整合データを炙り出すことができました。システムの規模や性質にもよりますが、わざわざこの観点専用にテスト仕様を作成しなくても、業務シナリオに基づいたテストで観点をカバーできていた気がします。

マイクロサービスアーキテクチャにおいては、かなり大掛かりなテストが必要になると思います。何よりも、CRUDの単位がサービスに変わります。ドメイン毎に分割された各サービスで分散してデータを保持する(しかも、データストアはRDBとは限らない!)ことになるので、各サービス担当者が雁首を揃えて、

  • 期待通りに各サービスのAPIが呼び出されたこと
  • 各サービスに分散して永続化されたデータが整合していること

を確認するテストになります。さらに言えば、上記を正常系だけでなく、補正トランザクションや冪等制御(リトライ)が発生する異常系に対しても実施する必要があります。

Pod/Taskの振舞い

「Pod」「Task」でピンときた方も多いと思いますが、システムの実行環境がKubernetes/AWS ECSの場合のテスト観点です。各サービスが実装したコンテナと共通チームやサードパーティが実装したサイドカーコンテナと組み合わせてPod/Taskにまとめ、クラスタ上で動作するかを検証するテスト観点です。

この連載自体は「マイクロサービスアーキテクチャに効く!テスト技法」ということで、特定の実行環境に限定した内容を意図してはいません。しかし、複数コンテナを1つの単位にまとめる場合(特に、OSSツールやクラウドベンダが開発したものなど、第三者が提供するコンテナを組み合わせてPod/Taskを構成する場合!)ならではの注意点があるため、敢えてテスト観点として挙げています。

このテスト観点で難しいのが、PodやTaskの外部仕様を把握してテストケースを立案する点です。各サービスの開発者は自身の開発したアプリケーションのコンテナについては外部仕様を把握できていると思います。しかし、そこに別の誰かが設計・実装したサイドカーを組み合わせた時に、どのような外部仕様になるかを各サービスの開発者が正確に理解できるでしょうか?

特に、Envoyで電文を動的に書き換えて通信制御を行う場合や、Daprでサービス間通信プロトコルを抽象化するケースなど、外部仕様が変化する場合に組み合わせる対象まで把握が必要になります。アプリケーションのコンテナを開発したチームがPod/Taskを構成するのであれば何とかなるかもしれませんが、Pod/Taskを構成してデプロイするのは別チームの役割だったりすると、テストする仕様・担当が不明となるリスクが発生します。

まとめ

今回は「マイクロサービスアーキテクチャならではのテスト観点と課題」ということで、アジャイルテストの4象限を基に、マイクロサービスアーキテクチャではどのようなテスト観点が発生するかを考えてみました。

大量のテスト観点リストを見て「こんなにあるのか!大変だ!やっぱりモノリスのほうが楽だ!」なんて思われてしまうかもしれませんね(笑)。この連載はテストの技法を直接的テーマとしていますが、テスト技法以前に設計に立ち返ってテスタビリティを高めないとどうしようもない観点も多いです。

勿論、最初から全てのテスト観点を網羅しないと品質保証にならない、なんてことはありません。とは言え、ITエンジニアとして開発業務を行う以上、相応の責任は発生します。ローンチ当初は部分的でよいとして、システムの成長と品質期待水準の高まりに連動し、テスト観点を広く深くカバーできるよう育てていく必要があります。手を抜けないのがつらいところです。

誤解なきよう述べておきますが、2022年現在、リストアップした全てのテスト観点に対し、筆者自身が成熟したノウハウを保持しているわけではありません。これらテスト観点を網羅してCI/CDできているのは、マイクロサービスアーキテクチャに継続的に取り組んでいるメガベンチャーくらいでしょう。

ですが、当社でもマイクロサービスアーキテクチャを採用するプロジェクトが増えてきています。お客様、ならびに、我々自身のDXにあたって、さらなるアジリティ向上が求められており、その解決策をマイクロサービスアーキテクチャに見出そうとしています。

筆者はそれらプロジェクトを支援し、マイクロサービスアーキテクチャのテストにまつわる困りごとを発掘→解決→ナレッジ化して、さらなる別プロジェクトへトランスファーする活動を技術開発として実施しています。その活動で発掘した解決すべき課題のリストとして、このテスト観点リストを作成しました。言ってしまえば「プロダクトバックログ」であり、いつか形にしたいナレッジ集の目次です。

今後もプロジェクトの支援を通じてテスト観点リストをひとつひとつナレッジとして充足させていければいいなと思っています。公表できるものは本連載を通じて読者の皆様とも共有いたします。なので、皆様も是非、テストの困りごとをお寄せください。いっしょに解決策を考えていければ嬉しいですし、ゆくゆくはこの連載をテスト技法のナレッジが行き交う場にしていければ幸甚です。

引き続き、ご期待ください。