Serverless FrameworkやSAMなどのサーバーレスアプリを開発するためのフレームワークでは、Lambda関数をテストする手法として、LocalStackやDynamoDB localを用いてローカルでテストを実行することができます。しかし今回は、それよりも単体テストに近い様なテストをPythonのライブラリであるmotoを用いてboto3をモックし、lambdaのテストを簡単に行う方法を書いていこうと思います。
環境
- Python 3.6
- Serverless Framework 1.39.0
- boto3 1.9.208
- moto 1.3.13
使用例
lambda関数
ここではDynamoDBからアイテムを取得して、レスポンスする簡単なlambdaを作成しました。
import json
import boto3
from decimal_encoder import DecimalEncoder
def get_article(event, context):
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('article')
article_id = event['pathParameters']['article_id']
res = table.get_item(
Key={
"article_id": article_id
}
)
article = res.get('Item')
response = {
"statusCode": 200,
"body": json.dumps(article, cls=DecimalEncoder)
}
return response
テストコード
@mock_dynamodb2
を書くことによってその関数内のboto3のDynamoDB関係のライブラリをモックしてくれる様になります。GETメソッドをテストするときなどはあらかじめテーブルにデータが入っていてほしい場合があるかと思います。そういう時も、テストコード内で通常と同様にput_itemをすることでデータを入れることができます。
import unittest
import boto3
from moto import mock_dynamodb2
from handler import get_article
from test.utility import init_dynamodb
class TestEvent(unittest.TestCase):
@mock_dynamodb2
def test_get_article(self):
# articleテーブルを作成
init_dynamodb()
# テストのためのarticleを一つ追加
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('article')
item = {
'article_id': 1,
'title': 'test_title',
'body': 'test_article_body',
}
table.put_item(Item=item)
# lambdaに渡すパラメーターを設定
event = {
'pathParameters': {
'article_id': 1
}
}
# 関数を実行
response = get_article(event, [])
print(response)
# {'statusCode': 200, 'body': '{"article_id": 1, "title": "test_title", "body": "test_article_body"}'}
# テスト
self.assertEqual(200, response['statusCode'])
ちなみに、init_dynamodb()の内容は以下の様になっていて、articleというテーブルを事前に作成しています。この様な形で必要なテーブルを全て事前に作成することで、簡潔で綺麗なテストコードにすることができます。
import boto3
from moto import mock_dynamodb2
@mock_dynamodb2
def init_dynamodb():
dynamodb = boto3.resource('dynamodb')
dynamodb.create_table(**{
'TableName': 'article',
'AttributeDefinitions': [
{
'AttributeName': 'article_id',
'AttributeType': 'N'
}
],
'KeySchema': [
{
'AttributeName': 'article_id',
'KeyType': 'HASH'
}
],
'ProvisionedThroughput': {
'ReadCapacityUnits': 1,
'WriteCapacityUnits': 1
}
})
まとめ
今回はDynamoDBの機能だけしか使いませんでしたがmotoでは、同様にして様々なAWSのサービスをモック化することができます。対応しているサービスはmotoのgithubに詳しく書いてあるので興味のある人は読んでみてください。サーバーレスアプリのテスト手法の一つとして非常に便利そうなので、ぜひ活用してみてください。