メインコンテンツまでスキップ

ローカル実行によるデバッグとテスト

アプリケーションコードをローカル開発環境で実行しデバッグを行う方法とテストの方法を記載したドキュメントです。

概要

AWS Lambda は Amazon API Gateway 起動(Web API)でも Event 起動でも同じく handler 関数の第一引数 event に処理に必要なデータが入っています。この Event Payload をあらかじめ作成してローカル実行ることで Lambda の動きを再現します。

処理の中で Amazon DynamoDB や S3 など他の AWS サービスと連携する場合は、AWS Lambda 実行ロールの代わりにローカル環境にセットされている AWS 認証情報( 環境変数のアクセスキー または ~/.aws/credentials )が利用されます。docker-compose で minio, dynamodb-local を起動していて AWS SDK にそれらのエンドポイントが記載されている場合、それらのコンテナに接続されます。

以下よりイベントペイロードを指定する例を確認いただけます。

  • WebAPI ロジック

    • API Gateway (REST API) から渡されるAPI呼び出しのリクエストペイロードを直接指定する形で、API ルーティングライブラリのインターフェースに合わせ、ハンドラー関数を実行しています。
      • .local/sample-api/get-users.ts
      • .local/sample-api/post_users.ts
  • Event 起動

    • S3・SNS・SQSなどから渡されるイベントペイロードを直接指定し、ハンドラー関数を実行しています。
      • .local/sample-event/post-s3-event.ts

イベントペイロードのテンプレートは、AWS Lambda のコンソールから取得できます。S3 イベントの場合「S3 Put」、API Gateway (REST API) の場合は「API Gateway AWS Proxy」を選択してください。

ローカル実行の手順

※「ローカル環境」とは、本カタログで立ち上げた EC2 インスタンスの環境を指します。

1. Dockerの立ち上げ

ローカル開発は専用のpythonスクリプトと、PostgreSQLのコンテナ及びS3の互換ストレージであるMinIOのコンテナを使って行います。まずはdocker-compose.yamlに定義されているこれらのコンテナを起動しましょう。

[ec2-user ~] docker compose up -d

2. DBセットアップ(Table作成)

コンテナで起動したPostgreSQL内にデータベースとテーブルを作成します。以下のPythonスクリプトでデータベースとusersテーブルをコンテナ内に自動作成してくれます。

[ec2-user ~] npx tsx .local/setup-db.ts

一方、スクリプトを利用せず、直接 psql という PostgreSQL のコマンドラインツールもインストール済みなのでそれを使ってコンテナ内のテーブルの操作を行うことも可能です。ここでは3件データを作成しています。パスワードが求められますが、password と入力してください。

[ec2-user ~]psql -h localhost -U admin -d mydb

mydb=# INSERT INTO users (name, country, age) VALUES
('Alice', 'Japan', 30),
('Bob', 'USA', 25),
('Charlie', 'Germany', 35);

mydb=# exit #これで通常のターミナルに戻れます

3. APIのローカル実行

GETのAPI

.local/sample-api/get-users.ts はGETメソッドでユーザデータを取得するAPIをシュミレートしたスクリプトです。ファイル内のリクエスト作成箇所を変更しながらデバッグや動作確認が可能です。

// Dynamic import after environment variables are set
const { api } = await import('../../src/sample-api')

// Test user ID - change this value to test different cases
const userId = 1

const response = await api.app.request(`/v1/users/${userId}`, {
method: 'GET',
})

const body = await response.json()
[ec2-user ~] npx tsx .local/sample-api/get-users.ts
API Execution Result: {"statusCode": 200, "body": "{\"statusCode\":200,\"body\":{\"name\":\"Alice\",\"country\":\"Japan\",\"age\":30}}", "isBase64Encoded": false, "headers": {"Content-Type": "application/json"}, "cookies": []}

実際にスクリプトを走らせるとAPIからのレスポンスが返ってきます。

POSTのAPI

.local/sample-api/post_users.ts はPOSTメソッドでユーザを作成するAPIをシュミレートします。今回は以下Bodyパラメータを操作しながら開発が可能です。

  // Dynamic import after environment variables are set
const { api } = await import('../../src/sample-api')

// Test data - change this to test different cases
const userData = {
name: 'Hanako',
country: 'Japan',
age: 25,
}

const response = await api.app.request('/v1/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData),
})

const body = await response.json()

実際にスクリプトを実行すると正しくBodyに設定されたデータが作成されていることが分かります。

[ec2-user ~] npx tsx .local/sample-api/create-users.ts
API Execution Result: {"statusCode": 200, "body": "{\"statusCode\":200,\"body\":{\"message\":\"The data created successfully.\"}}", "isBase64Encoded": false, "headers": {"Content-Type": "application/json"}, "cookies": []}

$ mydb=# SELECT * FROM users WHERE id=4;
id | name | country | age
----+--------+---------+-----
4 | Shigeo | Japan | 30
(1 row)

4. S3イベントのローカル実行

S3イベントではMinIOというS3互換ストレージを使ってテストします。以下スクリプトを実行するとMinIO上にtest-bucketというバケットを作成して、sample_users.csvをアップロードします。

[ec2-user ~] npx tsx .local/setup-minio.ts

MinIOでは直接Lambdaをトリガーするところまでは再現できません。なので、.local/sample-event/process-s3-event.ts でLambdaがトリガーされた時のイベントを生成し、ローカル実行を可能としています。スクリプトを実行するとsample_users.csvの内容がDB内に生成されていることが分かります。

[ec2-user ~] npx tsx .local/sample-event/process-s3-event.ts
mydb=# SELECT * FROM users;
id | name | country | age
----+---------+---------+-----
1 | Alice | Japan | 30
2 | Bob | USA | 25
3 | Charlie | Germany | 35
4 | Shigeo | Japan | 30
5 | Taro | Japan | 30
6 | Alice | USA | 28
7 | Bob | UK | 35
8 | Maria | Germany | 25
9 | Li | China | 32

5. ユニットテスト

ユニットテストもサンプルの実装を提供しています。pytestを使って、testsディレクトリの配下にテストコードが配置されています。ユニットテストも同様にPostgreSQLとMinIOのコンテナを使って、バリデーションのパターンや正常系のパターンなど必要と思われるテストケースを実装しています。

テストは以下のコマンドで実行できます。

[ec2-user ~] npm run test

その他のテスト方法

ローカル環境で擬似的な環境を立ち上げる

WebAPI ロジックの場合、SAM Local ( start-api ) を利用して localhost にて Amazon API Gateway をエミュレーションした API サーバーを立ち上げることが可能です。

Event 起動の場合、以下のようなものでローカル環境で AWS サービスをエミュレーションしてテスト等を行うことが可能です。