最初に作る時いつもどうやるんだっけ?となるのでメモ。
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することを確認する。
コメント
コメント一覧 (2件)
Requested resource not foundとなりませんか?
あれ、ほんとですか。すみません、後ほど確認してみます。