サーバーレス関数とアプリケーションをテストする方法 - AWS Lambda

サーバーレス関数とアプリケーションをテストする方法

サーバーレス関数のテストでは、従来のテストタイプと手法を使用しますが、サーバーレスアプリケーション全体のテストも検討する必要があります。クラウドベースのテストでは、関数とサーバーレスアプリケーションの両方の品質を最も正確に測定できます。

サーバーレスアプリケーションアーキテクチャには、API 呼び出しを通じて重要なアプリケーション機能を提供するマネージドサービスが含まれます。このため、開発サイクルには、関数とサービスが相互に作用する際に機能を検証する自動テストを含める必要があります。

クラウドベースのテストを作成しない場合、ローカル環境とデプロイされた環境の違いにより問題が発生する可能性があります。継続的な統合プロセスでは、コードをQA、ステージング、本番稼働などの次のデプロイ環境に昇格する前に、クラウドにプロビジョニングされた一連のリソースに対してテストを実行する必要があります。

サーバーレスアプリケーションのテスト戦略に関する詳細については、このショートガイドを引き続きご覧ください。また、サーバーレステストサンプルリポジトリにアクセスして、選択した言語とランタイムに固有の実用的な例を調べることもできます。

illustration showing the relationship between types of tests

サーバーレステストの場合も、ユニットテスト、統合テスト、エンドツーエンドテストを書くことになります。

  • ユニットテスト - 分離されたコードブロックに対して実行されるテスト。例えば、特定の商品と配送先を指定して配送料を計算するビジネスロジックを検証する場合です。

  • 統合テスト - 通常はクラウド環境で相互作用する 2 つ以上のコンポーネントまたはサービスを対象としたテスト。例えば、キューからのイベントを処理する関数を検証する場合です。

  • エンドツーエンドテスト - アプリケーション全体の動作を検証するテスト。例えば、インフラストラクチャが正しく設定され、顧客の注文を記録するためにイベントがサービス間で想定どおりに流れることを確認する場合です。

ターゲットを絞ったビジネス成果

サーバーレスソリューションのテストでは、サービス間のイベント駆動型の相互作用を検証するテストの設定にさらに少し時間がかかる場合があります。このガイドを読む際には、以下のビジネス上の目的を念頭に置いてください。

  • アプリケーションの品質を向上させる

  • 機能の構築とバグ修正に必要な時間を短縮する

アプリケーションの品質は、さまざまなシナリオをテストして機能を検証するかどうかにかかっています。ビジネスシナリオを慎重に検討し、それらのテストをクラウドサービスに対して実行するように自動化することで、アプリケーションの品質が向上します。

ソフトウェアのバグや構成上の問題は、反復的な開発サイクルで発見されても、コストやスケジュールへの影響は最小限で済みます。開発中に問題が発見されないままになっていると、本番環境での発見と修正時により多くの人員による取り組みが必要になります。

サーバーレステスト戦略を綿密に計画すれば、Lambda 関数とアプリケーションがクラウド環境で期待どおりに動作することを検証することで、ソフトウェアの品質が向上し、反復時間が短縮されます。

テスト対象

マネージドサービスの動作、クラウド構成、セキュリティポリシー、コードとの統合をテストして、ソフトウェアの品質を向上させるテスト戦略を採用することをお勧めします。ブラックボックステストとも呼ばれる動作テストでは、内部構造のすべてを考慮せずに、システムが期待どおりに動作することを検証します。

  • ユニットテストを実行して Lambda 関数内のビジネスロジックを確認します。

  • 統合サービスが実際に呼び出されることと、入力パラメータが正しいことを検証します。

  • イベントがワークフロー内で想定されるすべてのサービスをエンドツーエンドで通過することを確認します。

従来のサーバーベースのアーキテクチャでは、多くの場合、チームはテスト範囲にアプリケーションサーバー上で実行されるコードのみを含めるように定義していました。他のコンポーネント、サービス、依存関係はしばしば対象外とされ、テストの範囲から除外されていました。

通常、サーバーレスアプリケーションは、データベースからの製品取得、キューからの項目処理、ストレージ内の画像サイズ変更などを行う Lambda 関数のような小さな作業単位で構成されています。各コンポーネントは独自の環境で実行されます。こういった 1 つのアプリケーション内の小さなユニットの多くは、チームが担うことになるでしょう。

アプリケーション機能の中には、Amazon S3 などのマネージドサービスに完全に委任するものも、社内で開発したコードを使用せずに作成できるものもあります。これらのマネージドサービスのテストは不要ですが、これらのサービスとの統合についてはテストを実行する必要があります。

サーバーレスをテストする方法

ローカルにデプロイされたアプリケーションをテストする方法についてはご存知かと思います。つまり、デスクトップのオペレーティングシステムのみで動作するコードや、コンテナ内で動作するコードに対して実行するテストを書きます。例えば、リクエストを使用してローカルの Web サービスコンポーネントを呼び出し、そのレスポンスについてアサーションを実行できます。

サーバーレスソリューションは、関数コードと、キュー、データベース、イベントバス、メッセージングシステムなどのクラウドベースのマネージドサービスで構築されます。これらのコンポーネントはすべてイベント駆動型アーキテクチャを介して接続され、あるリソースから別のリソースにイベントと呼ばれるメッセージが流れます。このような相互作用は、同期的なアクション (Web サービスが直ちに結果を返すなど) の場合もあれば、後で完了する非同期的アクション (キューへのアイテムの配置やワークフローステップの開始など) の場合もあります。テスト戦略には両方のシナリオを含めて、サービス間の相互作用をテストする必要があります。非同期的な相互作用の場合、直ちに確認できないダウンストリームコンポーネントで発生する副作用の検出の必要が生じる可能性があります。

キュー、データベーステーブル、イベントバス、セキュリティポリシーなどを含むクラウド環境全体を複製することは現実的ではありません。ローカル環境とクラウドにデプロイされた環境の違いにより、必然的に問題が発生します。環境によって違いがあると、バグの再現と修正に要する時間が長くなります。

サーバーレスアプリケーションでは、アーキテクチャコンポーネントは通常すべてクラウドに存在するため、機能の開発やバグの修正には、クラウド内のコードとサービスに対してテストする必要があります。

テストのテクニック

実際には、テスト戦略にはソリューションの品質を向上させるためのさまざまな手法が含まれる可能性があります。簡単なインタラクティブテストを使用してコンソールで機能をデバッグする、自動ユニットテストを使用して分離されたビジネスロジックをチェックする、外部サービスへの呼び出しをモックで検証する、サービスを模倣するエミュレーターに対して時々テストを実行するなどの手法があります。

  • クラウドでのテスト - インフラストラクチャとコードをデプロイして、実際のサービス、セキュリティポリシー、構成、インフラストラクチャ固有のパラメータでテストします。クラウドベースのテストは、コードの品質を最も正確に測定できます。

    コンソールで関数をデバッグすると、クラウドで簡単にテストできます。サンプルテストイベントのライブラリから選択することも、カスタムイベントを作成して関数を個別にテストすることもできます。コンソールからテストイベントをチームと共有することもできます。

    開発およびビルドライフサイクルのテストを自動化するには、コンソールの外部でテストする必要があります。自動化戦略とリソースについては、このガイドの言語固有のテストセクションを参照してください。

  • モックを使ったテスト (フェイクとも呼ばれます) - モックとは、外部サービスをシミュレートして代用するコード内のオブジェクトです。モックには、サービスコールとパラメータを検証するための動作があらかじめ定義されています。フェイクとは、ショートカットを用いてパフォーマンスを単純化または改善する模擬実装のことです。例えば、フェイクのデータアクセスオブジェクトが、インメモリデータストアからデータを返す場合などです。モックは複雑な依存関係を模倣して単純化できますが、ネストされた依存関係を置き換えるためにモックが増えてしまうこともあります。

  • エミュレータによるテスト - ローカル環境のクラウドサービスを模倣するアプリケーション (サードパーティ製の場合もあります) をセットアップできます。利点は高速であることですが、セットアップが必要であることと、本番環境のサービスとの同等性が課題となります。エミュレータを使いすぎないようにしてください。

クラウドでのテスト

クラウドでのテストは、ユニットテスト、統合テスト、エンドツーエンドテストなど、テストのあらゆる段階で役立ちます。クラウドベースのサービスと相互作用するクラウドベースのコードに対してテストを実行すると、コードの品質を最も正確に測定できます。

クラウドで Lambda 関数を実行する便利な方法は、AWS Management Console でテストイベントを行うことです。テストイベントとは、関数への JSON 入力のことです。関数が入力を必要としない場合、イベントは空の JSON ドキュメント ({}) にすることができます。コンソールには、さまざまなサービス統合のサンプルイベントが用意されています。コンソールでイベントを作成したら、それをチームと共有して、テストを簡単かつ一貫性のあるものにすることもできます。

コンソールでサンプル関数をデバッグする方法を学びましょう。

注記

コンソールで関数を実行することはデバッグを簡単に実行する方法ですが、アプリケーションの品質と開発速度を向上させるには、テストサイクルを自動化することが不可欠です。

テスト自動化のサンプルは、サーバーレステストサンプルリポジトリで入手できます。以下のコマンドラインは、自動化された Python 統合テストの例を実行します。

python -m pytest -s tests/integration -v

テストはローカルで実行されますが、クラウドベースのリソースと相互に作用します。これらのリソースは、AWS Serverless Application Model および AWS SAM コマンドラインツールを使用してデプロイされています。テストコードは、まず API エンドポイント、関数 ARN、セキュリティロールを含む、デプロイされたスタック出力を取得します。次に、テストは API エンドポイントにリクエストを送信し、API エンドポイントは Amazon S3 バケットのリストを返します。このテストは、すべてクラウドベースのリソースに対して実行され、それらのリソースがデプロイされ、保護され、期待どおりに機能することを検証します。

========================= test session starts ========================= platform darwin -- Python 3.10.10, pytest-7.3.1, pluggy-1.0.0 -- /Users/t/code/aws/serverless-test-samples/python-test-samples/apigw-lambda/venv/bin/python cachedir: .pytest_cache rootdir: /Users/t/code/aws/serverless-test-samples/python-test-samples/apigw-lambda plugins: mock-3.10.0 collected 1 item tests/integration/test_api_gateway.py::TestApiGateway::test_api_gateway --> Stack outputs: HelloWorldApi = https://p7teqs3162.execute-api.us-west-2.amazonaws.com/Prod/hello/ > API Gateway endpoint URL for Prod stage for Hello World function PythonTestDemo = arn:aws:lambda:us-west-2:1234567890:function:testing-apigw-lambda-PythonTestDemo-iSij8evaTdxl > Hello World Lambda Function ARN PythonTestDemoIamRole = arn:aws:iam::1234567890:role/testing-apigw-lambda-PythonTestDemoRole-IZELQQ9MG4HQ > Implicit IAM Role created for Hello World function --> Found API endpoint for "testing-apigw-lambda" stack... --> https://p7teqs3162.execute-api.us-west-2.amazonaws.com/Prod/hello/ API Gateway response: amplify-dev-123456789-deployment|myapp-prod-p-loggingbucket-123456|s3-java-bucket-123456789 PASSED ========================= 1 passed in 1.53s =========================

クラウドネイティブアプリケーション開発の場合、クラウドでテストすることには次の利点があります。

  • 利用可能なすべてのサービスをテストできます。

  • 常に最新のサービス API と戻り値を使用します。

  • クラウドテスト環境は、実稼働環境によく似ています。

  • テストには、セキュリティポリシー、Service Quotas、構成、インフラストラクチャ固有のパラメータが含まれます。

  • すべてのデベロッパーは、クラウドで 1 つ以上のテスト環境をすばやく作成できます。

  • クラウドテストにより、コードが本番環境で正しく実行される精度が高まります。

クラウドでのテストにはいくつかの欠点があります。クラウドでのテストの最も明らかな欠点は、通常、クラウド環境へのデプロイはローカルデスクトップ環境へのデプロイよりも時間がかかることです。

幸い、AWSサーバーレスアプリケーションモデル (AWS SAM) AccelerateAWSCloud Development Kit (AWS CDK) 監視モードSST (サードパーティ) などのツールを使用すると、クラウドデプロイの繰り返しに伴うレイテンシーが軽減されます。これらのツールはインフラストラクチャとコードを監視し、自動的に増分アップデートをクラウド環境にデプロイできます。

注記

AWS Serverless Application Model、AWS CloudFormation、AWS Cloud Development Kit (AWS CDK) の詳細については、『サーバーレスデベロッパーガイド』の「インフラストラクチャをコードとして作成する方法」を参照してください。

ローカルテストとは異なり、クラウドでのテストには追加のリソースが必要で、サービスコストが発生する可能性があります。独立したテスト環境を作成すると、特にアカウントやインフラストラクチャを厳格に管理している組織では、DevOps チームの負担が増える場合があります。それでも、複雑なインフラストラクチャシナリオを扱う場合、複雑なローカル環境のセットアップと保守に要するデベロッパーの時間のコストは、Infrastructure as Code 自動化ツールで作成された使い捨てのテスト環境を使用する場合と同等 (またはそれ以上のコスト) になる可能性があります。

これらの考慮事項がありますが、サーバーレスソリューションの品質を保証するには、クラウドでのテストが依然として最善の方法です。

モックを使ったテスト

モックを使ったテストは、コード内に置換オブジェクトを作成してクラウドサービスの動作をシミュレートする手法です。

例えば、CreateObject メソッドが呼び出されるたびに特定の応答を返す Amazon S3 サービスのモックを使用するテストを作成できます。テストを実行すると、モックは Amazon S3 やその他のサービスエンドポイントを呼び出さずに、プログラムされた応答を返します。

多くの場合、モックオブジェクトは、開発の手間を減らすためにモックフレームワークによって生成されます。モックフレームワークの中には汎用的なものもあれば、AWS サービスやリソースを模倣するための Python ライブラリである Moto など、AWS SDK 専用に設計されたものもあります。

モックオブジェクトは、一般にデベロッパーがテストコードの一部として作成または設定しますが、エミュレータはエミュレート対象のシステムと同じ方法で機能を公開するスタンドアロンアプリケーションであるという点が異なることに注意してください。

モックを使用することのメリットは次のとおりです。

  • モックは、API や Software as a Service (SaaS) プロバイダーなど、アプリケーションの制御が及ばないサードパーティのサービスを、それらのサービスに直接アクセスすることなくシミュレートできます。

  • モックは障害状態をテストするのに便利です。特にサービス停止など、状態のシミュレートが困難である場合に役立ちます。

  • モックを一度設定すれば、ローカルテストを迅速に行うことができます。

  • モックは事実上あらゆる種類のオブジェクトの代替動作を提供できるため、モック戦略はエミュレータよりも幅広いサービスを対象とすることができます。

  • 新しい機能や動作が利用可能になった場合、モックテストであればより迅速に対応できます。一般的なモックフレームワークを使用することで、更新された AWS SDK が利用可能になるとすぐに新機能をシミュレートできます。

モックテストには次のような欠点があります。

  • モックは通常、特にレスポンスを適切に模倣するためにさまざまなサービスからの戻り値を特定しようとする際に、かなりの分量のセットアップや設定が必要になります。

  • モックはデベロッパーが作成、設定し、管理しなければならないため、デベロッパーの責任が増大します。

  • サービスの API と戻り値を理解するため、場合によってはクラウドにアクセスする必要があります。

  • モックはメンテナンスが難しい場合があります。モックされたクラウド API シグネチャが変更されたり、戻り値のスキーマが変更されたりといった場合、モックを更新する必要があります。アプリケーションロジックを拡張して新しい API を呼び出す場合も、モックを更新する必要があります。

  • モックを使用するテストは、デスクトップ環境では合格しても、クラウドでは失敗する可能性があります。結果が現在の API と一致しない可能性もあります。サービス構成とクォータはテストできません。

  • モックフレームワークでは、AWS Identity and Access Management (IAM) ポリシーやクォータ制限のテストまたは検出には制限があります。認証が失敗した場合やクォータを超過した場合のシミュレーションにはモックの方が優れていますが、テストでは本番環境で実際にどのような結果になるかを判断することはできません。

エミュレーションによるテスト

エミュレータは、通常ローカルで実行される、AWS 本番環境サービスを模倣するアプリケーションです。

エミュレータには、クラウド版と同様の戻り値を提供する API があります。また、API 呼び出しによって開始される状態変化をシミュレートすることもできます。例えば、AWS SAM を使用して AWS SAM ローカルで関数を実行し、Lambda サービスをエミュレートすると、関数を迅速に呼び出すことができます。詳細については、AWS Serverless Application Model デベロッパーガイドAWS SAM ローカルを参照してください。

エミュレータを使ったテストには、次のようなメリットがあります。

  • エミュレータを使用すると、ローカルでの開発の反復やテストを迅速に行うことができます。

  • エミュレータは、ローカル環境でのコード開発に慣れているデベロッパーにとって馴染みやすい環境を提供します。例えば、n 層アプリケーションの開発に慣れていれば、本番環境で実行されているものと同様のデータベースエンジンとウェブサーバーをローカルマシン上で実行して、高速かつ隔離されたテスト機能をローカルで提供できる可能性があります。

  • エミュレーターはクラウドインフラストラクチャ (デベロッパーのクラウドアカウントなど) を変更する必要がないため、既存のテストパターンで簡単に実装できます。

エミュレータを使ったテストには、次のような欠点があります。

  • エミュレータは、特に CI/CD パイプラインで使用する場合、セットアップや複製が難しい場合があります。このため、IT スタッフや独自のソフトウェアを管理するデベロッパーのワークロードが増大する可能性があります。

  • エミュレートされた機能や API は、通常サービスの更新でラグが発生します。これにより、テストされたコードが実際の API と一致しないためにエラーが発生し、新機能の導入が妨げられる可能性があります。

  • エミュレータには、サポート、更新、バグ修正、機能パリティの強化が必要です。これらはエミュレータの作成者の責任となりますが、作成者はサードパーティ企業の場合もあります。

  • エミュレータを使用するテストはローカルでは成功するかもしれませんが、クラウドでは本番環境のセキュリティポリシー、サービス間の設定、Lambda クォータの超過などが原因で失敗する可能性があります。

  • 多くの AWS サービスにはエミュレータがありません。エミュレーションに依存していると、アプリケーションの一部について十分なテストを行うオプションが得られない可能性があります。

ベストプラクティス

以下のセクションでは、サーバーレスアプリケーションのテストを成功させるための推奨事項について説明します。

サーバーレステストサンプルリポジトリには、テストとテスト自動化の実用的な例があります。

クラウドでのテストを優先する

クラウドでのテストは、最も信頼性が高く、正確かつ完全なテスト範囲を提供します。クラウドのコンテキストでテストを実行すると、ビジネスロジックだけではなく、セキュリティポリシー、サービス構成、クォータ、最新の API シグネチャと戻り値も包括的にテストされます。

テストしやすいようにコードを構造化する

Lambda 固有のコードを主要なビジネスロジックから分離することで、テストと Lambda 関数を簡略化できます。

Lambda 関数ハンドラーは、イベントデータを取り込み、ビジネスロジックメソッドにとって重要な詳細のみを渡すスリムなアダプターである必要があります。この方法では、Lambda 固有の詳細を気にすることなく、ビジネスロジックを中心に包括的なテストを行うことができます。AWS Lambda 関数では、テスト対象のコンポーネントを作成および初期化するために複雑な環境や大量の依存関係を設定する必要はありません。

一般には、受信したイベントコンテキストオブジェクトからデータを抽出して検証し、その入力をビジネスロジックを実行するメソッドに送信するハンドラーを作成することになります。

開発のフィードバックループを高速化

開発フィードバックのループを高速化するためのツールやテクニックがあります。例えば、AWS SAM AccelerateAWSCDK 監視モードは、いずれもクラウド環境の更新に要する時間を短縮します。

GitHub のサーバーレステストサンプルリポジトリにあるサンプルでは、これらのテクニックをいくつか取り上げています。

また、ソース管理にチェックインした後だけではなく、開発中のできるだけ早い段階でクラウドリソースを作成してテストすることをお勧めします。この方法により、ソリューションを開発する際の調査と実験を迅速に行うことができます。さらに、開発マシンからのデプロイを自動化することで、クラウド構成の問題をより迅速に発見し、更新やコードレビュープロセスに費やす無駄な労力を削減できます。

統合テストに焦点を当てる

Lambda でアプリケーションを構築する場合、コンポーネントをまとめてテストすることがベストプラクティスです。

2 つ以上のアーキテクチャコンポーネントに対して実行されるテストは統合テストと呼ばれます。統合テストの目的は、コードがコンポーネント間でどのように実行されるかだけではなく、コードをホストする環境がどのように動作するかを理解することです。エンドツーエンドテストは、アプリケーション全体の動作を検証する、特殊なタイプの統合テストです。

統合テストを作成するには、アプリケーションをクラウド環境にデプロイします。これはローカル環境から行うことも、CI/CD パイプラインを介して行うこともできます。次に、テストを作成して、テスト対象システム (SUT) を実行し、予想される動作を検証します。

例えば、テスト対象のシステムは、API Gateway、Lambda、DynamoDB を使用するアプリケーションの可能性があります。テストでは、API Gateway エンドポイントに対して合成の HTTP 呼び出しを行い、応答に期待されるペイロードが含まれていることを検証できます。このテストでは、AWS Lambda コードが正しいことと、各サービスがリクエストを処理するように正しく設定されていること (サービス間の IAM 権限を含む) を検証します。さらに、DynamoDB の最大レコードサイズなどの Service Quotas が正しく設定されていることを確認するために、さまざまなサイズのレコードを書き込むようにテストを設計することもできます。

3 つのサービスで構成されるテスト対象のシステムを示す図。

分離テスト環境の構築

通常、クラウドでのテストには、テスト、データ、イベントが重複しないように、分離されたデベロッパー環境が必要です。

1 つの方法は、各デベロッパーに専用の AWS アカウントを提供することです。これにより、複数のデベロッパーが共有コードベースで作業する、リソースをデプロイする、API を呼び出すといった場合に発生する可能性のあるリソース命名との競合を回避できます。

自動テストプロセスでは、スタックごとに一意の名前を付けたリソースを作成する必要があります。例えば、AWS SAM CLI の sam deploy または sam sync コマンドがスタックを一意のプレフィックスで自動的に指定するように、スクリプトまたは TOML 設定ファイルを設定できます。

デベロッパーが AWS アカウントを共有するケースもあります。これは、運用やプロビジョニング、構成にコストがかかるリソースがスタック内に存在することに関係している可能性があります。例えば、データベースを共有すると、データのセットアップと適切なシードが容易になります。

デベロッパーがアカウントを共有する場合は、所有権を特定して重複を排除するための境界を設定する必要があります。これを行う 1 つの方法は、スタック名の前にデベロッパーのユーザー ID を付けることです。もう 1 つの一般的な方法は、コードブランチに基づいてスタックを設定することです。ブランチの境界があると、環境は分離されますが、デベロッパーはリレーショナルデータベースなどのリソースを共有できます。この方法は、デベロッパーが一度に複数のブランチで作業する場合のベストプラクティスです。

クラウドでのテストは、ユニットテスト、統合テスト、エンドツーエンドテストなど、テストのあらゆる段階で役立ちます。適切な分離を維持することは不可欠ですが、それでも QA 環境は本番環境にできるだけ近づける必要があります。このため、チームは QA 環境に変更管理プロセスを追加します。

本番稼働前環境と本番稼働環境では、一般にアカウントレベルで境界線が引かれます。これは、ノイズの多い近隣の問題からワークロードを隔離し、機密データを保護するための最小特権のセキュリティ制御を実装するためです。ワークロードにはクォータがあります。テストで本番環境 (ノイズの多い近隣) に割り当てられたノルマを消費したり、顧客データにアクセスしたりすることは望ましくありません。負荷テストは、本番環境のスタックから分離すべきもう 1 つのアクティビティです。

いずれの場合も、不要な支出を避けるために、環境にはアラートと制御を設定する必要があります。例えば、作成できるリソースのタイプ、階層、またはサイズを制限したり、推定コストが特定のしきい値を超えたときにメールアラートを送信したりすることができます。

分離されたビジネスロジックにはモックを使う

モックフレームワークは、高速なユニットテストを記述するための有用なツールです。特に、数学的計算や財務上の計算、シミュレーションなど、複雑な社内ビジネスロジックをテスト対象とする場合に役立ちます。テストケースや入力のバリエーションが多く、それらの入力によって他のクラウドサービスへの呼び出しのパターンや内容が変わらないユニットテストを目標とします。

モックを使ったユニットテストの対象となるコードは、クラウドでのテストでも対象とする必要があります。デベロッパーのラップトップ環境や構築用マシン環境は、クラウドの本番環境とは異なった形で構成される可能性があるため、これが推奨されます。例えば、Lambda 関数を特定の入力パラメータで実行すると、割り当てよりも多くのメモリや時間を使用する可能性があります。また、コードに同じ方法で設定されていない (またはまったく設定されていない) 環境変数が含まれており、その違いによってコードの動作が異なったり、失敗したりする可能性があります。

接続ポイントの数が増えるほど、必要なモックを実装する手間が増えるため、統合テストではモックの有用性は低下します。エンドツーエンドのテストではモックを使うべきではありません。これらのテストは一般にモックフレームワークでは簡単にシミュレートできない状態や複雑なロジックを扱うためです。

最後に、サービスコールの適切な実装を検証するためにモッククラウドサービスを使用することは避けてください。代わりに、クラウドでクラウドサービスを呼び出し、動作、設定、機能実装を検証してください。

エミュレータを使いすぎないようにしてください。

エミュレータは、開発チームの使うインターネット回線に制限がある、信頼性が低い、低速であるなど、一部のユースケースでは有用な場合があります。ただし、ほとんどの状況では、安易なエミュレータの使用を避けるべきです。

エミュレータの使用を回避することで、最新のサービス機能と最新の API を使って開発やイノベーションを行うことができます。機能の同等性を実現するために、ベンダーのリリースを待つ必要はありません。複数の開発システムや構築用マシンの購入と構成にかかる初期費用と継続的な費用を削減できます。さらに、多くのクラウドサービスではエミュレータが利用できないという問題を回避できます。エミュレーションに依存するテスト戦略では、サービスを使用することができない (その回避策が高額になる可能性もあります)、または十分テストされていないコードや構成が生成されるなどの問題が生じます。

テストにエミュレーションを使用する場合でも、構成を検証したり、エミュレートされた環境でのみシミュレートまたはモックが可能なクラウドサービスとの相互作用をテストしたりするには、やはりクラウドでテストする必要があります。

ローカルでのテストの課題

エミュレータとモック呼び出しを使用してローカルデスクトップでテストする場合、CI/CD パイプラインの環境間でコードが進行するにしたがって、テストの不整合が発生する可能性があります。デスクトップ上でアプリケーションのビジネスロジックを検証するユニットテストでは、クラウドサービスの重要な側面を正確にテストできない場合があります。

以下の例は、モックやエミュレータを使ってローカルでテストする場合に注意すべきケースを示しています。

例: Lambda 関数が S3 バケットを作成する

Lambda 関数のロジックが S3 バケットの作成に依存している場合は、Amazon S3 が呼び出され、バケットが正常に作成されたことを完全なテストで確認する必要があります。

  • モックテストの設定では、成功レスポンスをモックし、失敗レスポンスを処理するテストケースを追加することもあります。

  • エミュレーションテストのシナリオでは、CreateBucket API が呼び出される場合がありますが、ローカル呼び出しを行う ID は Lambda サービスから発信されたものではないことに注意する必要があります。発信者 ID は、クラウド内のようにセキュリティ上の役割を果たさないため、代わりにプレースホルダー認証が使用されます。この場合、クラウドで実行する場合と異なり、ロールやユーザー ID はそれほど厳密なものではありません。

モックとエミュレーションのセットアップでは、Lambda 関数が Amazon S3 を呼び出した場合の動作をテストしますが、これらのテストでは、Lambda 関数が設定どおりに Amazon S3 バケットを正常に作成できるかどうかは検証されません。機能に割り当てられたロールに、その機能が s3:CreateBucket アクションを実行できるようにするセキュリティポリシーがアタッチされていることを確認する必要があります。アタッチされていない場合、関数はクラウド環境へのデプロイ時に失敗する可能性があります。

例: Lambda 関数を使用して、Amazon SQS キューからのメッセージを処理する

Amazon SQS キューが Lambda 関数のソースである場合は、テストを完了して、メッセージがキューに入った際に Lambda 関数が正常に呼び出されることを確認する必要があります。

エミュレーションテストとモックテストは通常、Lambda 関数コードを直接実行し、関数ハンドラーの入力として JSON イベントペイロード (または逆シリアル化されたオブジェクト) を渡して Amazon SQS 統合をシミュレートするように設定されます。

Amazon SQS 統合をシミュレートするローカルテストでは、特定のペイロードで Amazon SQS から呼び出されたときに Lambda 関数がどのように実行されるかをテストしますが、クラウド環境にデプロイされたときに Amazon SQS が Lambda 関数を正常に呼び出すかどうかは検証しません。

Amazon SQS と Lambda で発生する可能性のある設定の問題として、次のような例があります。

  • Amazon SQS の可視性タイムアウトが短すぎるため、意図された 1 回のみの呼び出しが複数回発生する。

  • Lambda 関数の実行ロールが、キュー (sqs:ReceiveMessagesqs:DeleteMessagesqs:GetQueueAttributes を経由) からのメッセージ読み取りを許可しない。

  • Lambda 関数に渡されるサンプルイベントが Amazon SQS メッセージサイズクォータを超えている。したがって、Amazon SQS ではそのサイズのメッセージは送信できず、テストが無効になる。

これらの例が示すように、ビジネスロジックは対象とするがクラウドサービス間の構成は対象としないテストでは、信頼性の低い結果が得られる可能性があります。

よくある質問

他のサービスを呼び出さずに計算を実行して結果を返す Lambda 関数があります。本当にクラウドでテストする必要がありますか?

はい。Lambda 関数には、テストの結果を変更する可能性のある設定パラメータがあります。すべての Lambda 関数コードはタイムアウトメモリの設定に依存しているため、これらの設定が正しく設定されていないと関数が失敗する可能性があります。Lambda ポリシーでは、Amazon CloudWatch への標準出力ロギングも可能です。コードが CloudWatch を直接呼び出さない場合でも、ロギングを有効にするには権限が必要です。この必要な権限を正確にモックしたりエミュレートしたりすることはできません。

クラウドでのテストはユニットテストにどのように役立ちますか? クラウド内にあり他のリソースに接続しているとしたら、それは統合テストではありませんか?

ユニットテストとは、アーキテクチャのコンポーネントを個別に操作するテストと定義していますが、他のサービスを呼び出したり、何らかのネットワーク通信を使用するコンポーネントをテストに含めたりといった内容が除外されるわけではありません。

多くのサーバーレスアプリケーションには、クラウドでも個別にテストできるアーキテクチャコンポーネントがあります。1 つの例として、入力を受け付け、データを処理し、Amazon SQS キューにメッセージを送信する Lambda 関数があります。この関数のユニットテストは、入力値によってキューに入れられたメッセージに特定の値が存在するかどうかをテストするといったものになります。

例えば、アレンジ、アクト、アサートというパターンで書かれたテストを考えてみましょう。

  • アレンジ: リソース (メッセージを受信するキュー、およびテスト対象の関数) を割り当てます。

  • アクト: テスト対象の関数を呼び出します。

  • アサート: 関数から送信されたメッセージを取得し、出力を検証します。

モックテストのアプローチでは、プロセス内のモックオブジェクトでキューをモックし、Lambda 関数コードを含むクラスまたはモジュールのプロセス内インスタンスを作成します。アサート段階では、キューに入れられたメッセージはモックされたオブジェクトから取得されます。

クラウドベースのアプローチでは、テスト用に Amazon SQS キューを作成し、分離された Amazon SQS キューを出力先として使用するように設定された環境変数を使用して Lambda 関数をデプロイします。Lambda 関数の実行後に、テストでメッセージを Amazon SQS キューから取得します。

クラウドベースのテストでは、同じコードを実行し、同じ動作をアサートして、アプリケーションの機能が正しいことを検証します。ただし、Lambda 関数の設定 (IAM ロール、IAM ポリシー、関数のタイムアウトとメモリの設定) を検証できるという利点もあります。

次のステップとリソース

実際のテスト例の詳細については、以下のリソースを参照してください。

実装例

GitHub の サーバーレステストサンプルリポジトリには、このガイドで説明されているパターンとベストプラクティスに従ったテストの具体例が含まれています。リポジトリには、前のセクションで説明したモック、エミュレーション、クラウドテストプロセスのサンプルコードとガイド付きウォークスルーが含まれています。このリポジトリを使用して、AWS の最新サーバーレステストガイダンスをご利用ください。

詳細情報

Serverless Land で、AWSサーバーレステクノロジーに関する最新のブログ、ビデオ、トレーニングにアクセスできます。

次の AWS ブログ記事を読むこともお勧めします。

ツール