LoginSignup
1
1

motoのmock_dynamodbを使ってみました

Last updated at Posted at 2023-12-27

やりたいこと

LambdaでDynamoDBからデータを取得するプログラムの単体テストをやるため、DynamoDB関連の処理をモック化したい

前提

・Pythonインストール済み
・pipenvインストール済み
(今回は便宜上pipenv内でtoxでテストをやるのですが、ローカルで諸々ライブラリを入れてテストをやっても大丈夫です)

ディレクトリ構成

root      
  ┣━ functions
      ┗━ api
          ┗━ app.py
  ┣━ tests
      ┣━ conftest.py
      ┗━ test_app.py
  ┣━ Pipfile
  ┗━ tox.ini

ソースの中身

ごく簡単の処理ですが、あるDynamoDBテーブルからget_itemをやりたい

app.py
import boto3
import os

# DynamoDB関連情報はLambdaの環境変数から取る
DYNAMO_TABLE_NAME = os.environ.get('DYNAMO_TABLE_NAME')
DYNAMO_REGION = os.environ.get('DYNAMO_REGION', default="ap-southeast-1")
dynamodb = boto3.resource('dynamodb', region_name=DYNAMO_REGION)

def lambda_handler(event):
    # keyの値はリクエストbody値から取る
    id = event['body']['id']
    name = event['body']['name']
    
    key = {
            'id': id,
            'name': name,
        }
    data = dynamodb.Table(DYNAMO_TABLE_NAME).get_item(Key=key)

    return data

テスト時は本物のDynamoDBにアクセスしないように、テストの前準備として、motoでmock化したDynamoDBテーブルを作りDummyのデータをputする関数を用意しておきます。

これは、単体テストを実行するとき、先にmock_tableが実行され、create_authority_table関数を返すような処理です。

conftest.py
import pytest
import boto3


DYNAMO_REGION = 'ap-southeast-1'
DYNAMO_TABLE_NAME = 'auth_table'


@pytest.fixture(scope='package')
def mock_table():
    def create_authority_table():
        ddb = boto3.resource('dynamodb', region_name=DYNAMO_REGION)
        # Dummyテーブルを作る
        table = ddb.create_table(
            TableName=DYNAMO_TABLE_NAME ,
            KeySchema=[
                {
                    'AttributeName': 'id',
                    'KeyType': 'HASH'
                },
                {
                    'AttributeName': 'name',
                    'KeyType': 'RANGE'
                },
            ],
            AttributeDefinitions=[
                {
                    'AttributeName': 'id',
                    'AttributeType': 'S'
                },
                {
                    'AttributeName': 'name',
                    'AttributeType': 'S'
                },
            ],
            ProvisionedThroughput={
                'ReadCapacityUnits': 1,
                'WriteCapacityUnits': 1
            }
        )

        # ちょっと待ち時間を置く
        table.wait_until_exists()

        # Dummyデータ投入
        table.put_item(
                Item={
                    'id': '0001',
                    'name': 'satoh',
                    'company': 'A',
                },
        )

        return ddb.Table(DYNAMO_TABLE_NAME)
    return create_authority_table

@mock_dynamodb()を書くと、本物のDynamoDBを見ずに、mock_tableで作られたテーブルを見に行くことになります。

test_app.py
import importlib
import pytest
from moto import mock_dynamodb


@pytest.mark.describe("Lambdaの単体テスト")
class TestLambda:
    @pytest.mark.it("正常系")
    @mock_dynamodb()
    def test_lambda_handler_success(self, mock_table):
        # テスト対象をimport
        from functions.api import app
        importlib.reload(app)

        # mock_tableの戻り値であるcreate_authority_tableを実行
        # 前処理のほうではmock_tableを実行しておくだけなので
        # create_authority_tableはこちらでやる
        mock_table()

        # テストデータを用意
        event = {'body': {'id': '0001', 'name': 'satoh'}}

        # テスト対象を呼び出す
        data = app.lambda_handler(event)

        # 検証
        assert len(data) != 0

終わりに

今回は実行時のキャプチャーを省略しますが、mock_dynamodbの書き方を試してみました

1
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
1
1