かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

boto3 のインスタンス生成をグローバルで行っても moto を利用したユニットテストを成功させるには?

概要

記事一覧はこちらです。

moto を利用したユニットテストが成功しなくなるので boto3 のインスタンス生成を Lambda のハンドラー関数内で行うようにしていましたが、aws-lambda-powertools を試してみる(Tracer&X-Ray 編その2) で boto3 のインスタンス生成をグローバルで行った方が処理にかかる時間が短くなることが判明したため、boto3 のインスタンス生成をグローバルで行っても moto を利用したユニットテストが成功する方法を調べることにします。

今回は resize-image-app-project プロジェクトで作成した AWS Lambda のユニットテストを作成する(local動作版)ユニットテストを行った resize-image-app-project プロジェクトを使用します。

参照したサイト・書籍

  1. What about those pesky imports?
    https://github.com/spulec/moto#what-about-those-pesky-imports

目次

  1. テスト対象のモジュールの import 文はテスト関数内に記述する

手順

テスト対象のモジュールの import 文はテスト関数内に記述する

moto の GitHubWhat about those pesky imports? に解決方法が書かれていました。import 文が関数の中に書けるとは思いませんでした。

resize_service/handler.py で s3_client = boto3.client('s3') を記述する位置をハンドラー(resize 関数)の外側に移動してから、

import logging
import os
import re
import uuid
from urllib.parse import unquote_plus

import boto3
from PIL import Image

thumbnail_size = 320, 180

logger = logging.getLogger()
logger.setLevel(logging.INFO)

s3_client = boto3.client('s3')


def resize_image(image_path, resized_path):
    with Image.open(image_path) as image:
        image.thumbnail(thumbnail_size)
        image.save(resized_path)


def resize(event, context):
    for record in event['Records']:
        ..........

テストクラスの外に書いている from resize_service import handler を、

import json
import unittest

import boto3
from moto import mock_s3

from resize_service import handler


@mock_s3
class TestResizeService(unittest.TestCase):
    ..........

    def test_resize(self):
        s3_client = boto3.client('s3')
        s3_client.upload_file('tests/sample.jpg', TestResizeService.UPLOAD_BUCKET, 'sample.jpg')

        with open('tests/s3_event.json', 'r') as f:
            event = json.load(f)

        handler.resize(event, None)

        ..........

テスト関数内に移動します。

import json
import unittest

import boto3
from moto import mock_s3


@mock_s3
class TestResizeService(unittest.TestCase):
    ..........

    def test_resize(self):
        from resize_service import handler

        s3_client = boto3.client('s3')
        s3_client.upload_file('tests/sample.jpg', TestResizeService.UPLOAD_BUCKET, 'sample.jpg')

        with open('tests/s3_event.json', 'r') as f:
            event = json.load(f)

        handler.resize(event, None)

        ..........

python -m unittest -v を実行するとテストは成功し、

f:id:ksby:20200707000454p:plain

IntelliJ IDEA 上でテストを実行しても問題なく成功します。

f:id:ksby:20200707000613p:plain

Docker 上で実行する方法も試してみましたが、問題なく成功しました。

履歴

2020/07/07
初版発行。