【boto3】DynamoDBの自動テストで使えるかもしれないスニペット
LocalStackのようなエミュレータを活用したテストコードでよく使うやつ。
- Python 3.8.3
- boto3 1.16.14
- pytest 6.1.2
ここで記載するサンプルメソッドは下のようなクラスに所属している前提になります。
import boto3 import mypy_boto3_dynamodb.service_resource as dynamodb_resources class DynamoDefiner: dynamo: dynamodb_resources.DynamoDBServiceResource def __init__(self, endpoint_url: str = None): dynamo: dynamodb_resources.DynamoDBServiceResource = boto3.resource( "dynamodb", endpoint_url=endpoint_url ) self.dynamo = dynamo
テーブルがない場合は作成
def create_my_table(self, table_name: str) -> None: # すでにテーブルがあるかチェック (二重にテーブルを作成しようとするとエラーになるため) tables = list(self.dynamo.tables.all().__iter__()) if list(filter(lambda t: t.name == table_name, tables)): # すでにある場合は終了 return self.dynamo.create_table( TableName=table_name, KeySchema=[ {"AttributeName": "partition_key", "KeyType": "HASH"}, {"AttributeName": "sort_key", "KeyType": "RANGE"}, ], AttributeDefinitions=[ {"AttributeName": "partition_key", "AttributeType": "S"}, {"AttributeName": "sort_key", "AttributeType": "S"}, ], BillingMode="PAY_PER_REQUEST", # GSI貼る場合 GlobalSecondaryIndexes=[ { "IndexName": "sort_key-index", "KeySchema": [ {"AttributeName": "sort_key", "KeyType": "HASH"}, ], "Projection": { "ProjectionType": "ALL", }, }, ], )
テーブルのItemを全件削除
def clear_my_table(self, table_name: str) -> None: my_table = self.dynamo.Table(table_name) # scanでItems取得 scanning_result = my_table.scan() items = scanning_result["Items"] # 0件なら終了 if not items: return # scanで取得したItemsを全件削除 # TODO batch_writeに変えたら高速化できそう for item in items: shop_table.delete_item( Key={"shop_id": item["shop_id"], "sort_key": item["sort_key"]} ) # 再帰 self.clear_shop_table(table_name)
1回のscanで全件取得できるとは限らないため、取得しきれなかった場合は再帰呼び出しで繰り返すようにしています。
使い方
テストフレームワークはpytest、DynamoエミュレータはLocalStackを使用しているものとします。
setupでテスト毎に
- テーブルがなければ作成
- テーブルのクリア
をします。
import boto3 import mypy_boto3_dynamodb.service_resource as dynamodb_resources class TestShopDynamoRepository(object): def setup_method(self) -> None: dynamoDefiner = DynamoDefiner(endpoint_url="http://localhost:4566") dynamoDefiner.create_shop_table("my-table") dynamoDefiner.clear_shop_table("my-table")
こうすると前のテストの状態に依存しないように各テストを実施できます。