AWS

【AWS】SAMのLambdaのpythonのpytest

更新日:

はじめに

SAMのテンプレートに沿ってLambdaをpythonで書いたはいいものの、pytestでテストコード書くのにハマったので基本的な使い方のサンプル作ってみました。

以下の方を対象としてます。
・pythonを真面目に学習したことはないが、Lambdaでライトにpythonを使いたい。
・単純なロジックしかないし、1からpythonを学習するのは面倒。
・ノリでLambdaをpythonでコーディングしたものの、pytestがわからん。
・SAMのテンプレートを利用してに沿ったpytestのサンプルが欲しい

筆者自身が上記の状態でしたが、段々わかってきたので同じような方向けにサンプルを作成しました。
pythonに詳しいわけではないため、誤りなどあればご指摘いただけると助かります。

github(サンプルコード)はこちら
以降はサンプルコードのうち、ポイント(筆者がハマった)部分をかいつまんで説明してます。
おそらく本サンプルをベースに不明点をググれば、最低限のpytestは作成できると勝手に思ってます。

requirements.txt

pythonコードの実行に必要なライブラリを記載します。
テスト対象で利用しているライブラリも記載する必要があります。
今回は最低限のライブラリしか記載してません。

tests/requirements.txt

ライブラリのインストールは以下コマンド
※CI等でpytestを自動実行する場合は、実行前にライブラリのインストールが必要です。

実行コマンド

通常はpycharmなどのIDE上で実行するかと思いますが、CIなどで自動一括実行する場合は以下のコマンドを指定します。

__init__.py

pythonは実行時のカレントディレクトリを意識します。
故に別ファイル(.py)に記載したモジュールをimportするためには、相対パスを指定する必要があります。
加えて、SAMテンプレートのようにテスト用モジュールからテスト対象モジュールを読めないディレクトリ(モジュール)構成になっている場合はパスを通す必要があります。

今回のサンプルではモジュール実行時の初期化処理である__init__.pyにパスを通す処理を記載してます。
ついでにboto3(AWSのpython用SDK)のモックであるmotoを利用する場合、デフォルトのリージョン指定がないと意図しない挙動となることがあるてため、__init__.pyへ記載してます。
(本サンプルではmotoは扱ってません。ぐぐればたくさん情報出てきます。)

tests/unit/init.py

テスト対象モジュール

テスト対象モジュールです。
API Gatewayとのプロキシ統合を意識した戻り値としてますが、やっていることは単純に別モジュール(sub_app.py)のメソッド(return_value)を呼び出しているだけです。
また、カスタム例外のモックも(筆者自身がどハマりしたので)扱うため、例外も別モジュール(custom_exception.py)に定義してます。

src/app.py

sub_app.py

custom_exception.py

テスト用モジュール

サンプルのメインとなるテスト用モジュールです。
注意点を順番に記載します。

コードはこちら

クラス名とモジュール名

クラス名は「Test」、モジュール名は「test_」から始まる命名をする必要があります。
別の命名をするとテスト対象として認識されず、pytest実行時にテストが実行されません。
(知らないと以外とハマります)

逆にユーティリティの場合は、別の命名とする必要があります。

モック

mocker.patchを利用することでモック化できます。
メインとなる(と勝手に思ってる)利用方法は2種類あります。

1. mocker.patch(モック対象メソッドの文字列指定, return_value=返却する値)
2. mocker.patch(モック対象メソッドの文字列指定, side_effect=例外のインスタンス や 関数)

1は単純に返却する値を指定する場合に利用します。
2は例外の発生や、返す値を可変にする際に利用します。
※本サンプルで例外の発生のみで利用してます。

ここで筆者がドハマったのは引数の指定方法です。
テスト対象モジュールでimportしているメソッドを指定する必要があります。

具体的には、

sub_appからimportしたreturn_valueをモックしてCustomExceptionを発生させるには

src.app配下のパスを指定する必要があります。
筆者はテストモジュールでモック対象のモジュールをimportして、importしたモジュールを指定してしまいドハマってました。

ただし、テスト対象モジュールでimportしていないモジュールはテストモジュールでimportして例外を指定する必要があります。(たとえば、↓のサンプル

ちなみに、mocker.patchを変数へ格納すれば呼出回数のassertも可能です。

例外のassert

pytest.raisesを利用し、発生した例外をassertします。

ログのassert

caplogを利用し、loggerで出力された内容をassertできます。

テストコードの全体像

-AWS

Copyright© 若手SIerサラリーマンの独学メモ , 2024 All Rights Reserved Powered by STINGER.