APIテストとは何か、APIテストの正攻法

最近の導入支援で、顧客と一緒にAPIテスト戦略を構築していたら、突然「APIテストとは何ですか」と尋ねられました。その時に私は、APIテストを説明するのは非常に難しいということに気付いたのです。たとえそれを説明できたとしても、退屈で複雑なものという印象を与えがちです。

さて、私がこの記事でお伝えしたいのは、APIテストは退屈でも複雑でもないということです。実際には、APIテストは非常に面白く、強力です。きちんと理解すれば、真に効果的なテスト戦略を生み出す力が得られます。

APIとは何か、なぜAPIを使用するのか

サービス開発において、アプリケーションプログラムインターフェイス(API)とは、さまざまなアプリケーションが、共通言語を使用して互いに通信する手段です。この共通言語は、多くの場合コントラクトによって定義されます。具体的な例としては、RESTfulサービスのSwaggerドキュメントやSOAPサービスのWSDLです。データベースの場合でも、インターフェイス言語、つまりSQLがあります。

UIが人間とアプリケーションとのやりとりを可能にするのと同様に、APIを使用すると、マシン間の通信が効率的に行えます。

APIの利点は、部品であることです。APIを使用すると、マシン間の通信が必要になるたびにインターフェイスを書き換えることなく、あらゆる種類のインタラクションを簡単に組み立てることができます。さらに、APIにはコントラクトがあるため、相互に通信するアプリケーションは、APIコントラクトに従って通信する限り、どんなふうに構築することもできます。これにより、世界中のさまざまな組織のさまざまな開発者が、同じAPIを再利用して高度な分散アプリケーションを作成できます。

ユーザーがアプリケーションのフロントエンド(たとえばモバイルアプリなど)とやり取りするとき、そのフロントエンドはバックエンドシステムへのAPI呼び出しを行います。これは主に次の2つの点で開発プロセスを簡略化します。

  1. 開発者は、モバイルデバイスやブラウザーごとにカスタマイズされたアプリケーションを作成する必要がない
  2. アプリケーション全体を毎回再デプロイせずに、個々のAPI(バックエンド)を改修するだけでアプリケーションを素早くバージョンアップできる

その結果、開発者は、アプリケーション全体のロジックを作り込むことに時間を費やすのではなく、APIで部品化することで、個々のAPI(サービス)で独立した機能を提供することに集中できるため、開発を効率化できます。

標準APIの使用例

AmazonショッピングサービスのAPIを利用すると、開発者はアプリケーションを作成する際にAmazonショッピングと連携することができます。開発者は、ユーザーエクスペリエンスの適切なタイミングでAmazon APIを使用して、顧客にシームレスな動線を提供できます。

たとえば、次のようなケースです。

ユーザーエクスペリエンス 対応するAPI呼び出し
1.    面白そうなビデオゲームを探す 1.     ItemSearch
2.    AmazonはMinecraftを提案 2.     ItemLookup
3.    Minecraftをカートに入れる 3.     CartCreate
4.     CartAdd

ユーザーがアプリケーションのフロントエンド(たとえばモバイルアプリなど)とやり取りするとき、フロントエンドは開発者が設定した定義に従ってバックエンドのAmazon APIと対話します。基礎となるAPIが期待どおりに動作している限り、すべてがうまく機能します。

……しかし、APIが期待通りに動作すると仮定するのは非常に危険です。

そこで、APIをテストすることが重要だという認識に至ります。

なぜAPIテストを行うのか?

開発者とテスト担当者は、UIレベルでのみアプリケーションとやり取りをするユーザーとは異なり、基礎となるAPIの信頼性を保証する必要があります。 API自体をテストしなければ、開発者やテスト担当者は、ユーザーと同じように UIレベルでアプリケーションをテストすることになり、アプリケーションスタック全体が構築されるまでテストを開始できません。

幸いなことに、UIと切り離して、APIテストを実行する方法があります。基盤となるAPIと直接対話するテストケースを設計し、API レベルでアプリケーションをテストすることで、主に次の2つの利点があります。

  1. UIからの操作ではテストしにくいケースであってもAPIなら直接テストできる
  2. APIはUIと比較して作りが単純であるため、テスト資産のメンテナンスの容易さも含め、自動化に向いている

セミナー開催中!

ハンズオンセミナー開催中!

previous arrow
next arrow
Slider

APIテストへのアプローチ

APIテストにアプローチする最善の方法は、ボトムアップ的に堅固なテストプラクティスを構築することです。その際、テスト戦略の設計方法として非常に優れているのは、Martin Fowlerのテストピラミッドに従うことです。このピラミッド型のアプローチでは、堅固なユニットテストの基盤の上に、幅広いAPIテスト(コントラクト、シナリオ、パフォーマンスなど)を構築することが推奨されます。APIテストは、ユニットテストでは不可能なレベルでアプリケーションロジックをテストできます。

ユニットテストとAPIテストは互いを補完します。SDLC(ソフトウェアディベロップメントライフサイクル)の後半ではなく、早期に低いレベルでアプリケーションをテストすることは、「fail fast and fail early」つまり早期に欠陥を検出するのに役立ちます。 ユニットテストは重要ですが、今回の記事では特にAPIテストについて取り上げます。では、どのようなAPIテストがあるのでしょうか?APIテストはなぜ重要なのでしょうか?どのようにAPIテストを実施すればよいのでしょうか?

以下のセクションでは、さまざまなタイプのAPIテストについて、使いどころや利点なども含めて説明します。

コントラクトテスト

APIは、2つ以上のアプリケーション間の連携をコントラクト(APIの仕様を記述した設計書のようなもの)に基づいて行います。コントラクトには、インターフェイスとの通信方法、利用可能なサービス、呼び出し方法などを記述されており、コミュニケーションの基礎となります。コントラクトに誤りがある場合、どうしようもありません。

最初に行う最も基本的なタイプのAPIテストは、サービスコントラクト自体(Swagger、PACT、WSDLまたはRAML)をテストするコントラクトテストです。このタイプのテストでは、コントラクトが正しく書かれており、クライアントによって処理できることを検証します。このテストでは、コントラクトを読み込んで以下を検証するテストを作成します:

  • サービスコントラクトが仕様に従って記述されている
  • メッセージ要求と応答のセマンティクスが正しい(スキーマ検証)
  • エンドポイントが有効である(HTTP、MQ / JMSトピック/キューなど)
  • サービスコントラクトが変更されていない

これらは最初に行う「スモークテスト」と考えられます。これらのテストが失敗した場合、そのサービスを引き続きテストする意味はありません。これらのテストに合格してはじめて、APIの実際の機能のテストを開始できます。

コンポーネントテスト

コンポーネントテストは、APIに対するユニットテストのようなものです。つまり、APIで利用可能な個々のメソッドを個別にテストします。コンポーネントテストを作成するには、サービスコントラクトで利用可能な各メソッドまたはリソースに対応するテストステップを作成します。

コンポーネントテストを作成する最も簡単な方法は、サービスコントラクトを読み込んで自動的にテストクライアントを作成することです。その後、正常系と異常系のデータを使用して個々のテストケースをデータ駆動し、返されたレスポンスが次のような特性を持つことを検証します。

  • リクエストのペイロードが整形式である(スキーマの検証)
  • レスポンスのペイロードが整形式である(スキーマの検証)
  • レスポンスのステータスが期待どおりである(200 OK、SQL結果セットが返される、またはエラーが期待される場合はエラーが返される)
  • レスポンスエラーペイロードに正しいエラーメッセージが含まれている
  • レスポンスが期待されるベースラインと一致する。これには2つの検証方法があります。
    • 回帰/差分 – レスポンスのペイロードが、異なる呼び出しで全く同じであること(基本的にレスポンスのスナップショットを取得し、毎回検証するトップダウンアプローチ)。これはAPIの変更を検出するための有効な手段にもなります(詳細は後で説明します)。
    • アサーション – レスポンスの個々の要素が期待を満たしている(これは、レスポンスの特定の値を対象としたより局所的なボトムアップのアプローチです)。
  • サービスが期待された時間内に応答する

これらのAPIテストは、後続のすべてのテスト手法で活用されるため、とても重要なテストです。コンポーネントテストで個々のAPI呼び出しを作成しておけば、その後のテストでは作成済みのAPI呼び出しを利用してテストケースを作成できるので、新たに一からテストケースを作成する必要がありませんこのようにテストを再利用すると、一貫性が促進されるだけでなく、APIテストを実現するためのプロセスも簡素化されます。

シナリオテスト

シナリオテストは、APIテストといったときに、ほとんどの人が思い浮かべるテストです。このテスト手法では、上記のAmazonサービスの例と同様に、個々のコンポーネントテストを一連のシーケンスに組み立てます。

処理の流れを取得するには2つの方法があります:

  1. ユーザーストーリーを確認して、個々のAPI呼び出しを特定する
  2. UIを操作し、背後のAPIに対して行われるトラフィックを取得する

シナリオテストでは、異なるデータポイント(APIで取得したデータを用いて、異なるAPIからデータを取得するなど)を組み合わせたときに欠陥がないかどうかを理解できます。

私は、顧客と一緒に仕事をする中で、これについて非常に興味深い例に遭遇しました。彼らは、顧客の財務プロフィール、利用可能なアカウント、クレジットカード、および最近の取引を呼び出すのに、一連のサービスを使っていました。これらのAPI呼び出しは、個別には正しく動作していましたが、シーケンスにまとめると失敗するようになりました。この理由は、単純なタイムスタンプであることが判明しました。1つのAPI呼び出しから返されたタイムスタンプが、後続のリクエストで期待される形式とは異なる形式であったことが原因でした。ユニットテストやスモークテストでは、形式を指定せずにタイムスタンプが返されたことだけをアサーションしていたため、問題を捕捉できませんでした。全体的なシナリオをテストして初めて、ある呼び出しから別の呼び出しにタイムスタンプを渡すと、エラーの原因になることが明らかになりました。

シナリオテストのもう1つの利点は、想定していない方法でAPIが利用された時の動作を検証できることです。APIをリリースするということは、材料となるブロックを世界中に提供するということです。ブロックを組み合わせる方法を規定しておいたとしても、顧客は予想外の要望を持つことがあり、想定していない方法でAPIを組み合わせ、結果としてアプリケーションの不具合を露呈させることがあります。これを防止するために、APIをさまざまに組み合わせて多数のシナリオテストを作成し、アプリケーションを致命的なエラーから防護する必要があります。

シナリオテストを構成する要素としてコンポーネントテストが存在しているため、通常、シナリオテストの数は多くなります。シナリオテストは、新しい機能が導入されたときに構築され、新しい機能に関する顧客の動線をモデル化します。このやり方では、想定外の問題を補足するための基盤となる、信頼できるテストのライブラリがすでに存在しているとわかっているため、新しく追加された機能のテストを作成するだけで済み、テストに費やされる時間を大幅に短縮できます。

パフォーマンステスト

パフォーマンステストは、通常、パフォーマンステスト専用の環境で、テストプロセスの最後に実施されます。これは、パフォーマンステストソリューションが高価で、特殊なスキルセットを必要とし、特定のハードウェアと環境を必要とする場合が多いためです。APIにはサービスレベルアグリーメント(SLA)があり、アプリケーションをリリースするにはこれを満たす必要があるため、パフォーマンステストの遅延は大きな問題です。ぎりぎりまでパフォーマンステストの実施を保留した場合、SLAを満たすことができなかったら、大幅にリリースが遅延する可能性があります。

プロセスのより早い段階でパフォーマンステストを行うことで、完全な回帰サイクルを実行する前にパフォーマンス関連の問題を発見できます。この時点までにテストプロセスを実行している場合、パフォーマンステストを行うために必要な基本的なテストケースがすべてそろっているため、実際はかなり簡単になります。シナリオテストを パフォーマンステストツールにロードし、ユーザー数を増やして実行するだけです。これらのテストが失敗した場合は、個々のユーザーストーリーに戻って障害を追跡し、何が影響を受けるかをより明確に把握することができます。マネージャーは、この情報に基づいて、アプリケーションをリリースするかしないかについて決断を下すことができます。

セキュリティテスト

セキュリティテストは、組織内のすべての関係者にとって重要です。セキュリティ上の脆弱性が公開され、悪用されると、深刻なイメージダウンと金銭的ペナルティが発生する可能性があります。ユーザーが誤って予想外の方法でAPIを使用する可能性があるように、ユーザーは意図的にAPIを悪用しようとする可能性があります。ハッカーはAPIを入手し、脆弱性を発見し、それらを利用することができます。

この種の動作を防ぐためには、悪質な攻撃をシミュレートするテストケースを構築する必要があります。シナリオテストはアプリケーションへ故意に攻撃するシナリオも作成できるため、既存のテストケースをセキュリティテストに活用することができます。たとえば、さまざまなタイプのパラメーターファジングまたはSQLインジェクション攻撃をシナリオテストと組み合わせるのがよい例です。このようにすると、アプリケーション内に波及する変化があれば、セキュリティテストによって検出されます。APIセキュリティテストの詳細については、こちらの役に立つブログ記事をご覧ください。

オムニチャネルテスト

アプリケーションが相互連携するインターフェイスは複数あるため(モバイル、Web、API、データベースなど)、これらのインターフェイスのいずれかを単独でテストすると、テストカバレッジの不足が生じ、インタフェース間の複雑なやり取りの微妙な部分が失われます。

オムニチャネルテストは、APIとデータベーステストをモバイルやWeb UIの検証に組み込むことによって、アプリケーションの多数のインターフェイスを包括的にカバーし、完全なテストカバレッジを達成します。つまり、どれか1つのインターフェイスを操作するテストを別のインターフェイスのテストと組み合わせます。たとえば、Web(Selenium)またはモバイル(Appium)のUIテストの実行をAPIやデータベースのテストと組み合わせたり、システムのデータポイントを交換します。オムニチャンネルテストを効果的に実施すると、簡単に自動化でき、安定性が高く再利用可能なテストケースを作成できます。

変更管理

変更は、アプリケーションのリスクの最も重要な指標の1つです。変更には、以下のように多くの形態があります。

  • サービスのプロトコルメッセージフォーマットの変更
  • APIに追加または削除された要素
  • 返されるデータ形式に影響を与えるコード変更
  • サービスを複数の部分に分割するためのアーキテクチャの再構築(組織がマイクロサービスに移行する際に非常に一般的)

変更が発生した場合、変更を識別し、対応策を計画するためにテストケースを構築する必要があります。変更の影響に対処するための分析を提供するソリューションを使用すると、発生した変更を理解し、影響を受ける特定のテストだけを対象とすることができます。

変更をテンプレートの形式で取り込み、それを使って基礎となるコンポーネントまたはシナリオのテストを新しい機能に合うよう更新することができます。残りのテストではこれらのテストが参照されるため、変更の影響は軽減されます。

まとめ

堅牢なAPIテスト戦略を構築することは、アプリケーションが「今日も昨日と同じように動く」ことを保証するための最良の方法です。APIテストは、アプリケーションの複数のレイヤーで欠陥を検出するための堅牢なフレームワークを構築します。これらのテストはすべて自動化され、継続的に実行できるため、アプリケーションがビジネス上の期待を満たし、また正確に機能していることを保証できます。APIテストはUIテストよりもはるかに低いレベルで動作するため、一貫性があり、現在構築しているテストが今後も長期間にわたって利用できることがわかるでしょう。

(この記事は、開発元Parasoft社 Blog 「What is API testing, and are you doing it right?」2018年2月23日の翻訳記事です。)


Parasoft SOAtest/Virtualizeについて

 

APIのテスト自動化とサービス仮想化を1ツールで

SOAtest/Virtualizeは、APIの開発者/利用者に向けてテストの自動化とテスト環境の仮想化の2つの側面から開発を効率化します。SOAtest/Virtualizeは、APIのテストドライバーを提供し、開発中のAPIのテストを自動化する機能と、APIを利用するアプリケーションが必要とするAPIをスタブとして仮想化する機能を同梱して提供します。



Top