LoginSignup
2
1

More than 1 year has passed since last update.

sam initでPythonのLambdaを作成したときに、pytestが付いてくる

Posted at

はじめに

sam initでPythonのLambdaを指定した際、testsというフォルダが付いてきます。
Lambdaで単体テストを行いたいと思っていて、中がどうなっているのか確認してみましたので、その内容を記事にします。

概要

  • sam initでPythonのLambdaを作ると、pytest用のフォルダtestsが生成される
  • PythonのLambdaを作る場合は、pytestを使った方がよさそう

やったこと

環境

いつものClooud9です。コンテナを作るわけではないので、最安価インスタンスで十分かと思います。

sam init

まずはsamテンプレートを作ります。

$ mkdir dev
$ cd dev

$ sam init
Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1
What package type would you like to use?
        1 - Zip (artifact is a zip uploaded to S3)
        2 - Image (artifact is an image uploaded to an ECR image repository)
Package type: 1

Which runtime would you like to use?
        1 - nodejs14.x
        2 - python3.9
        3 - ruby2.7
        4 - go1.x
        5 - java11
        6 - dotnetcore3.1
        7 - nodejs12.x
        8 - nodejs10.x
        9 - python3.8
        10 - python3.7
        11 - python3.6
        12 - python2.7
        13 - ruby2.5
        14 - java8.al2
        15 - java8
        16 - dotnetcore2.1
Runtime: 2

Project name [sam-app]: samtest

Cloning from https://github.com/aws/aws-sam-cli-app-templates

AWS quick start application templates:
        1 - Hello World Example
        2 - EventBridge Hello World
        3 - EventBridge App from scratch (100+ Event Schemas)
        4 - Step Functions Sample App (Stock Trader)
        5 - Elastic File System Sample App
Template selection: 1

階層は以下の様になります。

$ pwd;find . | sort | sed '1d;s/^\.//;s/\/\([^/]*\)$/|--\1/;s/\/[^/|]*/|  /g'
/home/ec2-user/environment/dev
|--samtest
|  |--events
|  |  |--event.json
|  |--.gitignore
|  |--hello_world
|  |  |--app.py
|  |  |--__init__.py
|  |  |--requirements.txt
|  |--__init__.py
|  |--README.md
|  |--template.yaml
|  |--tests
|  |  |--__init__.py
|  |  |--integration
|  |  |  |--__init__.py
|  |  |  |--test_api_gateway.py
|  |  |--requirements.txt
|  |  |--unit
|  |  |  |--__init__.py
|  |  |  |--test_handler.py

コマンドは以下を使っています。

フォルダ階層の画像のほうも添付します。
image.png

tests以下のファイルを一つ見てみます。pytestをインポートしているのがわかります。

/dev/samtest/tests/unit/test_handler.py
import json

import pytest

from hello_world import app


@pytest.fixture()
def apigw_event():
    """ Generates API GW Event"""

    return {
        "body": '{ "test": "body"}',
以下略

テスト用仮想環境

実マシンに直接テスト用環境は用意せず、仮想環境上に作ろうと思います。テスト環境名は、sam initの環境名と同じにしてみました。
devフォルダ直下に作成しました。

python -m venv .venv/samtest
source .venv/samtest/bin/activate

必要なモジュールを仮想環境にインストールします。

pip3 install pytest
pip3 install boto3
# Lambdaでは必要なモジュールは以下のファイルに記載されているはずなので、それを使ってインストール
pip3 install -r samtest/hello_world/requirements.txt

pytest実行

対象のフォルダに移って、pytestを実行します。移動先はtestsフォルダのある階層になります。

cd samtest/
pytest tests

以下の様にエラーになりました。hello_worldフォルダが見つけられなかったようです。

====================================================================== test session starts ======================================================================
platform linux -- Python 3.7.10, pytest-7.2.0, pluggy-1.0.0
rootdir: /home/ec2-user/environment/dev/samtest
collected 1 item / 1 error                                                                                                                                      

============================================================================ ERRORS =============================================================================
__________________________________________________________ ERROR collecting tests/unit/test_handler.py __________________________________________________________
ImportError while importing test module '/home/ec2-user/environment/dev/samtest/tests/unit/test_handler.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/usr/lib64/python3.7/importlib/__init__.py:127: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
tests/unit/test_handler.py:5: in <module>
    from hello_world import app
E   ModuleNotFoundError: No module named 'hello_world'
==================================================================== short test summary info ====================================================================
ERROR tests/unit/test_handler.py
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
======================================================================= 1 error in 0.31s ========================================================================

python -m pytest testsと実行してもよいのですが、今回は以下を参考にパスを通してみます。

tests/conftest.py
import sys 
import os

sys.path.append(os.path.abspath(os.path.dirname(os.path.abspath(__file__)) + "/../"))

自作のモジュールなどをmodulesフォルダにおいて、そのファイルを単体テストしたい場合などは、さらにパスを追加すると良いかと思います。

パスを追加して実行した結果は、1つ成功、1つエラーになりましたが、pytest自体は動くことが確認できました。

====================================================================== test session starts ======================================================================
platform linux -- Python 3.7.10, pytest-7.2.0, pluggy-1.0.0
rootdir: /home/ec2-user/environment/dev/samtest
collected 2 items                                                                                                                                               

tests/integration/test_api_gateway.py E                                                                                                                   [ 50%]
tests/unit/test_handler.py .                                                                                                                              [100%]

============================================================================ ERRORS =============================================================================
_______________________________________________________ ERROR at setup of TestApiGateway.test_api_gateway _______________________________________________________

self = <samtest.tests.integration.test_api_gateway.TestApiGateway object at 0x7f1a320c9490>

    @pytest.fixture()
    def api_gateway_url(self):
        """ Get the API Gateway URL from Cloudformation Stack outputs """
        stack_name = os.environ.get("AWS_SAM_STACK_NAME")
    
        if stack_name is None:
>           raise ValueError('Please set the AWS_SAM_STACK_NAME environment variable to the name of your stack')
E           ValueError: Please set the AWS_SAM_STACK_NAME environment variable to the name of your stack

tests/integration/test_api_gateway.py:20: ValueError
==================================================================== short test summary info ====================================================================
ERROR tests/integration/test_api_gateway.py::TestApiGateway::test_api_gateway - ValueError: Please set the AWS_SAM_STACK_NAME environment variable to the name of your stack
================================================================== 1 passed, 1 error in 0.19s ===================================================================

以降のテスト

pythonの関数ごとのテストはpytestで出来ますが、Lambdaとしてのテストを行いたい場合は、以下の以前の記事を参考にしてください。

おわりに

以前から、生成されるtestsフォルダが気になっていたので、今回調べてみました。
これをきっかけにpytestの使い方も習得して、より安全にLambdaを作っていきたいと思います。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1