最初に作る時いつもどうやるんだっけ?となるのでメモ。
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することを確認する。
関連記事
aws の記事
- [2023年3月27日] Pythonで深いネストのlistやDictの値を調べてDecimalがあればint or floatに変換する
- ---本記事---
- [2023年3月18日] DynamoDBのテーブル設計をテキストで記述したいのでChatGPT-4に教えてもらった
- [2022年12月1日] CognitoのIDトークンをLambda関数で検証するサンプルコード
- [2022年7月11日] API Gateway + Cognito Authorizer + Lambda関数でeventから得られるjsonのメモ
- [2022年5月25日] DynamoDBにboto3で操作した時のレスポンス、エラー出る・出ない
- [2022年4月13日] RAK7246にBasic Stationを入れてAWS LoRaWAN NetworkServerに接続
- [2022年1月18日] 2022年1月18日 DyanmoDB、メタバース、アキネータ
- [2021年8月23日] AWS SAMでDynamoDBテーブルを作成する時のテンプレート
- [2021年6月12日] DynamoDBの多対多で隣接リストやった時の冗長性対策どうしよう
- [2021年5月13日] Lambda関数でDeadLetterQueue(DLQ)を試す
Python の記事
- [2023年4月29日] Python3: Ctrl-cで割り込み処理
- ---本記事---
- [2023年3月27日] Pythonで深いネストのlistやDictの値を調べてDecimalがあればint or floatに変換する
- [2021年11月18日] GKE + Flask で REST API
- [2019年5月23日] SendGridのAPIでPythonライブラリ(6.0.5)を使って添付ファイルを送信する
- [2019年4月4日] C1801: Do not use len(SEQUENCE) to determine if a sequence is empty (len-as-condition)と怒られた時
- [2019年4月3日] Python + SendGrid API でメールを送信する
- [2018年8月21日] boto3でS3にアップロードした画像が、ブラウザで表示するとダウンロードされてしまう時
- [2018年7月27日] Pandasで2列を比較してTrue/Falseの新たな列を作る。さらに1/0へのマッピング
- [2018年7月20日] pythonのpipで入れているもの
- [2018年6月25日] cronのpythonスクリプト内にあるjson.dump()でensure_ascii=Falseにして日本語出力しようとしてハマった
スポンサーリンク
Requested resource not foundとなりませんか?
あれ、ほんとですか。すみません、後ほど確認してみます。