📌
pytest/PynamoDB/moto(v5) な環境でのモック方法と fixture 作成例
概要
Python で API を開発しています。
一部のデータは DynamoDB で管理しており、DynamoDB とのやり取りには PynamoDB を利用しています。
pytest と moto(v5) を使ってテストを作成したのですが、モックの方法で少し苦戦したので、備忘録に書いておきます。
ちなみに筆者は Python 初心者です。
環境
- Python 3.8.12
- PynamoDB 5.5.1
- pytest 6.2.5
- moto 5.0.5
備忘録
以下、テスト作成までの記録になります。
DynamoDB 環境のモック
まず、DynamoDB 環境のモックです。conftest.py
に以下のコードを追加します。
import pytest
from moto import mock_aws # v5から mock_dynamodb はなくなった
# DynamoDB環境のモック
@mock_aws
@pytest.fixture(scope='session', autouse=True)
def mock_dynamodb():
mock = mock_aws()
mock.start() # mock_aws.start で DynamoDB のモックが行われる
UserRank.create_table()
# 他にも作成すべき DynamoDB テーブルのモックがあればここに追加
yield
mock.stop()
これで DynamoDB 環境のモックができました。
実際の DynamoDB とデータのやり取りをすることなく、レコードの作成や読み出しが可能となります。
fixture 生成関数
次に PynamoDB モデルの fixture 生成関数です。こちらも conftest.py
に追加。
from models import UserRank # PynamoDB の Model を継承して作成したモデル
# UserRank のfixture生成関数
@pytest.fixture
def dummy_user_rank_factory(dummy_user): # user は DynamoDB ではなく RDB で管理されるデータ
def f(
user=dummy_user,
rank=999,
):
UserRank(user_id=user.id, rank=rank).save()
return f
# 他にも DynamoDB テーブルがあれば、以下に fixture 生成関数を追加
テストコード作成
あとは、実際のテストコードで fixture 生成関数を利用すれば OK です。
class TestUserRankView:
def test_get(
self,
dummy_user_factory,
dummy_user_rank_factory,
):
user = dummy_user_rank_factory()
dummy_user_rank_factory(user=user, rank=10)
# /api/user_rank/<int:user_id> のようなAPIパスへのリクエスト
response = ...
assert response.json()['user']['id'] == user.id
assert response.json()['user']['rank'] == 10
以上。
ハマりポイント
以下、個人的にハマったポイント。
- PynamoDB モデルに
host
指定をしているが、このせいで実際の DynamoDB に接続してしまっていた。テスト実行時にhost
指定をしないよう修正。 - mock_aws の start() だけで DynamoDB のモックまでできるとは思わず、ドキュメントを探し続けてしまった。
Discussion