kakakakakku blog

Weekly Tech Blog: Keep on Learning!

Lambda 関数(コンテナ)をテストできる testcontainers-python v4.8.0 の新機能「AWSLambdaContainer」

2024年8月14日にリリースされた testcontainers-python v4.8.0 の新機能を確認していたら new: Added AWS Lambda module と書いてあって,これは何だろう〜と気になって試してみた❗️

github.com

簡単に言えば,テスト実行時に testcontainers-python で AWS Lambda 関数(コンテナ)を起動して,AWS Lambda RIE (Runtime Interface Emulator) エンドポイント /2015-03-31/functions/function/invocations を呼び出したレスポンスを assert できる機能だった💡AWS Lambda 関数(コンテナ)の振る舞いをデプロイする前にテストできる \( 'ω')/

さっそく AWSLambdaContainer を試す

ディレクトリ構成

.
├── Dockerfile
├── requirements-test.txt
├── src
│   └── app.py
└── tests
    └── test_app.py

👾 Dockerfile

まず Dockerfile を作る.Python ベースイメージを使えば AWS Lambda RIC (Runtime Interface Clients)AWS Lambda RIE (Runtime Interface Emulator) をセットアップしなくて OK👌 Ubuntu などをベースイメージにする場合は別途セットアップする必要がある.

docs.aws.amazon.com

FROM public.ecr.aws/lambda/python:3.12

COPY src/app.py ${LAMBDA_TASK_ROOT}

CMD [ "app.handler" ]

👾 src/app.py

AWS Lambda 関数で実行するコードはサンプルとして受け取った event をそのまま返す実装にした.

def handler(event, context):
    return event

👾 tests/test_app.py

以下のドキュメントを参考にしつつテストコードを書いてみた❗️

testcontainers-python.readthedocs.io

まず DockerImageDockerfile からコンテナイメージをビルドしつつ,AWSLambdaContainer で AWS Lambda 関数(コンテナ)を起動する💡そして send_request() で AWS Lambda RIE (Runtime Interface Emulator) のエンドポイント /2015-03-31/functions/function/invocations を呼び出す.

今回は4種類の assert を実装した👌

  • エンドポイント
  • ステータスコード
  • レスポンス (title)
  • レスポンス (url)
import re

from testcontainers.aws import AWSLambdaContainer
from testcontainers.core.image import DockerImage


def test_function():
    with DockerImage(path='.') as image:
        with AWSLambdaContainer(image=image, port=8080) as func:
            pattern = r'http://localhost:\d+/2015-03-31/functions/function/invocations'
            assert re.match(pattern, func.get_api_url())

            response = func.send_request(
                {
                    'title': 'kakakakakku blog',
                    'url': 'https://kakakakakku.hatenablog.com/',
                }
            )
            body = response.json()

            assert response.status_code == 200
            assert body['title'] == 'kakakakakku blog'
            assert body['url'] == 'https://kakakakakku.hatenablog.com/'

ちなみに get_api_url() という関数はドキュメントには載ってなかったけど,実装を確認しているときに発見した.ポート部分は毎回変わるけど http://localhost:61522/2015-03-31/functions/function/invocations という値が返ってくる😀 まさに RIE エンドポイント \( 'ω')/

github.com

👾 requirements-test.txt

AWSLambdaContainer の依存する ServerContainer は HTTP リクエストを操作するライブラリとして内部的に HTTPX を使っているようだった.

www.python-httpx.org

よって,AWSLambdaContainer のレスポンスは HTTPX オブジェクトになるため,セットアップを忘れると ModuleNotFoundError: No module named 'httpx' というエラーが出る.今回 requirements-test.txt は以下のようにした.

httpx==0.27.0
pytest==8.3.2
testcontainers==4.8.0

✅ 動作確認

OK👌

$ python -m pytest --verbose

tests/test_app.py::test_function PASSED                                                                                                                                     [100%]

まとめ

testcontainers-python v4.8.0 の新機能「AWSLambdaContainer」を試してみた❗️

ちなみに個人的には AWS Lambda 関数を実装するときは handler()main() を分割して,main() をテストしている.ドキュメントにもベストプラクティス「Lambda ハンドラーをコアロジックから分離します」と紹介されていたりする📝

docs.aws.amazon.com

今回の AWSLambdaContainer では AWS Lambda RIE (Runtime Interface Emulator) を使って AWS Lambda 関数(コンテナ)の振る舞いをテストできるため,あくまで個人的には単体テストとしてではなく統合テストとして活用できそうかなと思った.

関連記事

kakakakakku.hatenablog.com