🐍

pytest + MotoでS3, Secrets Managerのテストコードを書く

2024/05/02に公開

pytestとMotoでシンプルなテストコードを書いてみる。
pytestはもうすでにinstallしている前提です。

環境

  • Python: 3.11.9
  • moto: 5.0.6
  • pytest: 8.2.0

Motoとは

単体テストでAWSサービスをモックしてくれるライブラリ。
デコレーターを付与するだけで、boto3などで使用しているAWSサービスへの呼び出しが自動でモック化されます。
motoはpytestでAWSのAPIが呼び出されると、実際のAWSではなくmotoによって提供されるモックのAPIにルーティングし、モック化してくれます。
そのためテスト上で、仮想的なAWSリソースを作成・操作・削除が可能です。
また操作は全てメモリ内で行われ、実際のAWSアカウントには影響を与えないようになっています。

Install Moto

まだMotoをインストールしていない場合は、以下のコマンドでインストールする。
allにするとmotoで対応されているすべてのサービスがインストールされます。
対応されているサービス一覧

pip install 'moto[s3,secretsmanager]'
# or
pip install 'moto[all]'

S3とSecrets Managerを参照している関数をテストする

S3とSecrets Managerどちらもget系を記載。

S3

boto3のget_objectを使用している関数をテストしたい場合

テスト対象の関数
import boto3

def get_s3_object(bucket_name, key):
    s3 = boto3.client('s3')
    response = s3.get_object(Bucket=bucket_name, Key=key)
    return response['Body'].read()
テストコード
import boto3
import pytest
from moto import mock_aws

@mock_aws
def test_s3_bucket_creation():

    bucket_name = 'test-s3-bucket'
    key = 'test-object'
    body = b'dymmy contents for UT'

    # テスト用にS3バケットとオブジェクトを作成する
    s3 = boto3.client('s3')
    s3.create_bucket(Bucket=bucket_name)
    s3.put_object(Bucket=bucket_name, Key=key, Body=body)

    # テスト対象の関数を呼び出す
    retrieved_body = get_s3_object(bucket_name, key)

    assert retrieved_body == body

Secrets Manager

boto3のget_secret_valueを使用している関数をテストしたい場合

テスト対象の関数
import boto3

def get_secret_value(secret_name):
    client = boto3.client('secretsmanager', 'ap-north-east1')
    response = client.get_secret_value(SecretId=secret_name)
    return response['SecretString']
テストコード
import boto3
import pytest
from moto import mock_aws

@mock_aws
def test_get_secret_value():

    secret_name = 'test-secret'
    secret_value = 'my-secret-value'

    # テスト用にダミーのシークレットを作成する
    client = boto3.client('secretsmanager')
    client.create_secret(Name=secret_name, SecretString=secret_value)

    # テスト対象の関数を呼び出す
    retrieved_secret_value = get_secret_value(secret_name)

    assert retrieved_secret_value == secret_value

Fixtureを使用する

もしくはfixtureを使用して、s3のバケット作成やシークレット作成を事前にしておくのも良いです。

conftest.py
import boto3
import pytest
from moto import mock_secretsmanager

@pytest.fixture
def aws_resources():
    with mock_secretsmanager():
        client = boto3.client('secretsmanager')
        client.create_secret(Name='test-secret', SecretString='my-secret-value')
        yield client
テストコード
def test_get_secret_value(aws_resources):
    client = aws_resources
    retrieved_secret_value = get_secret_value('test-secret')
    assert retrieved_secret_value == 'my-secret-value'

参考

公式ドキュメント
https://docs.pytest.org/en/8.2.x/
https://docs.getmoto.org/en/latest/

Discussion