motoでDynamoDBのMockを作成する

最初に作る時いつもどうやるんだっけ?となるのでメモ。

motoを使ってDynamoDBのmock作る時のテンプレ。

目次

環境

  • Python 3.9.16
    • boto3==1.18.1
    • pytest==6.2.4
    • moto==4.0.5
  • macOS 12.6.3

ディレクトリ構造

func/app.py をテストする感じで。

.
├── func
│   ├── app.py
├── tests
│   ├── __init__.py
│   └── unit
│       ├── __init__.py
│       ├── conftest.py
│       ├── test_func
│       │   ├── test_app.py
│       ├── test_data.yml

func/app.py ではDynamoDBを操作している。test_app.pyでfunc.app.main()を動かすには、DynamoDBをpytestで実行できる必要がある。

テーブルはusersテーブルで、PK,SKのほかGSIを持つ。

func/app.py

import boto3

dynamo = boto3.resource('dynamodb')
table = dynamo.Table(os.environ['TABLE_USERS'])

def main():
  res = table.scan()
  print(res['Items'])
  return True

usersテーブルをスキャンする謎の関数。これをテストする。

test_data.yml

テストデータを記述する。taroさんだけ登録している寂しいテーブル。

environment:
  TABLE_USERS: "test_users"
  AWS_DEFAULT_REGION: "ap-northeast-1"
DynamoDB:
  TABLE_USERS:
    AttributeDefinitions:
      - AttributeName: user_id
        AttributeType: S
      - AttributeName: created_at
        AttributeType: N
      - AttributeName: user_name
        AttributeType: S
    KeySchema:
      - AttributeName: user_id
        KeyType: HASH
      - AttributeName: created_at
        KeyType: RANGE
    GlobalSecondaryIndexes:
      - IndexName: 'user_name-index'
        KeySchema:
          - AttributeName: user_name
            KeyType: HASH
        Projection:
          ProjectionType: ALL
  ITEMS_USERS:
    - user_id: user1
      created_at: 1600000000
      user_name: taro

地味に環境変数の設定もしている。GSIの設定が味噌。各種変数名は後述のconftest.pyで使うので、そこで合わせ込む。

conftest.py

テスト共通で読み込めるようにconftest.pyに以下を記述する。

import yaml
import os
import pytest
import boto3
from moto import mock_dynamodb


config_file = "tests/unit/test_data.yml"


@pytest.fixture(autouse=True)
def set_envs(monkeypatch):
    with open(config_file, "r", encoding="utf-8") as fp:
        envs = yaml.safe_load(fp)["environment"]

    for k, v in envs.items():
        monkeypatch.setenv(k, str(v))


@pytest.fixture(autouse=True)
def table():
    with mock_dynamodb():
        with open(config_file, "r", encoding="utf-8") as fp:
            test_data = yaml.safe_load(fp)["DynamoDB"]

        # users テーブルの作成
        table_config = test_data["TABLE_USERS"]
        dynamodb = boto3.resource("dynamodb")
        dynamodb.create_table(
            TableName=os.environ["TABLE_USERS"],
            AttributeDefinitions=table_config["AttributeDefinitions"],
            KeySchema=table_config["KeySchema"],
            GlobalSecondaryIndexes=table_config["GlobalSecondaryIndexes"],
            BillingMode="PAY_PER_REQUEST",
        )
        table = dynamodb.Table(os.environ["TABLE_USERS"])
        with table.batch_writer() as batch:
            for item in test_data["ITEMS_USERS"]:
                batch.put_item(Item=item)
    
        yield

これでテストコード中でusersテーブルを読み込めるようになる。

test_app.py

import pytest


def test_main():
    from func import app

    assert app.main()

main()を実行するだけの関数。

実行

func, testsのあるディレクトリから

pytest -vv -s /tests

を実行して、PASSすることを確認する。

本サイトはUXを悪くするevilなGoogle広告を消しました。応援してくださる方は おすすめガジェット を見ていってください!
よかったらシェアしてね!
  • URLをコピーしました!

コメント

コメント一覧 (2件)

コメントする

目次