LoginSignup
4
5

More than 3 years have passed since last update.

Serverless Frameworkでboto3をモックしてテストする

Posted at

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に詳しく書いてあるので興味のある人は読んでみてください。サーバーレスアプリのテスト手法の一つとして非常に便利そうなので、ぜひ活用してみてください。

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5