Python
unittest
Mock
boto3

boto3+mockでテスト

More than 1 year has passed since last update.


はじめに

boto3を使って、AWSのS3に対して操作をするようなコードを書きました。

テストコードを書いてみようと思い、mockとunittestを用いて作成することにしました。


準備

まずは環境の準備です。

適当なフォルダを作成してvirtualenvを使って環境を作ります。

今回はAWS Lambdaに乗せることを前提としています。

後、boto3とmockをpipしときます。


環境準備

$ mkdir s3operation

$ cd s3operation
$ virtualenv .
$ source bin/activate
$ pip install boto3
$ pip install moto


S3への操作するサンプルクラス

$ pwd

~/s3operation/
$ vi s3access.py


s3access.py

# -*- coding:utf-8 -*-

import boto3
import os.path

class S3Access:
s3 = None
def __init__(self):
self.s3 = boto3.client('s3')

def upload(self, bucketname, uploadfilepath, s3folder):
"""
S3へアップロード
@param bucketname S3バケット名
@param uploadfilepath アップロードするファイルのパス
@param s3folder S3バケットの下のフォルダパス(ファイル名は含まない)
"""

basefilename = os.path.basename(uploadfilepath)
s3filepath = s3folder + '/' + basefilename
self.s3.upload_file(uploadfilepath, bucketname, s3filepath)



テストコード

今回は、アップロードだけのプログラムにしました。

では、次にテストコードを作成します。まずは、環境構成を。


環境構成

今回のファイル/フォルダ構成です。

テストコードだけ、別のフォルダ(今回はtestフォルダ)に作成したかったので、以下のような感じにしています。

~/s3operation/

s3access.py
test/
testfile.txt
tests3access.py


テストコード

テストコードは以下のような感じです。


tests3access.py

# -*- coding:utf-8 -*-

import boto3
import unittest

from moto import mock_s3

import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../')
from s3access import S3Access

class TestS3Access(unittest.TestCase):
def setUp(self):
pass

def tearDown(self):
pass

@mock_s3
def test_s3_upload(self):
#初期化
bucketname = 'testbucket001'
prefix = 'firstfolder'

##テスト準備(バケット、オブジェクト作成)
s3test = boto3.client('s3')
s3test.create_bucket(Bucket=bucketname)
s3test.put_object(Bucket=bucketname, Key=prefix)

#テスト対象のオブジェクト生成
s3 = S3Access()
#対象メソッド実行
s3.upload('./test.md', bucketname, prefix)

#実行結果確認
##アップロード済みの情報をS3から読み込む
keyname = prefix + '/test.md'
response = s3test.get_object(Bucket=bucketname, Key=keyname)
body = response['Body'].read().decode('utf-8').encode('utf-8')
##アップロードしたファイルを読み込む
fp = open(filename, 'r')
readStr = fp.read()
fp.close
##結果確認
assert body2 == readStr



テスト実行

テストコードもできたので、実際にテストを実行します。

$ pwd

~/s3operation/test/
$ python -m unittest discover ./
.
----------------------------------------------------------------------
Ran 1 tests in 0.472s

OK

これで、一つのテストが実行されて成功したことになります。


失敗した場合

何かプログラムにエラーが存在する場合、以下のような感じになります。

エラー情報から解析して後は直すだけです。

python -m unittest discover ./

E
======================================================================
ERROR: test_s3_upload (tests3access.TestS3Access)
----------------------------------------------------------------------
Traceback (most recent call last):
File "~/s3operation/lib/python2.7/site-packages/moto/core/models.py", line 70, in wrapper
result = func(*args, **kwargs)
File "~/s3operation/test/tests3access.py", line 43, in test_s3_upload
response = s3test.get_object(Bucket=bucketname, Key=keyname)
File "~/s3operation/lib/python2.7/site-packages/botocore/client.py", line 310, in _api_call
return self._make_api_call(operation_name, kwargs)
File "~/s3operation/lib/python2.7/site-packages/botocore/client.py", line 599, in _make_api_call
raise error_class(parsed_response, operation_name)
NoSuchKey: An error occurred (NoSuchKey) when calling the GetObject operation: The specified key does not exist.

----------------------------------------------------------------------
Ran 6 tests in 0.519s

FAILED (errors=1)


さいごに

今回の例では、S3の一部だけの評価を書きましたが、他にも以下のAWSリソースにも対応しています。

- API Gateway

- AutoScaling

- CloudFormation

- CloudWatch

- DataPipeline

- DynamoDB

- EC2

- ECS

- ELB

- EMR

- Glacier

- IAM

- Lambda

- Kinesis

- KMS

- RDS

- Redshift

- Route53

- S3

- SES

- SNS

- SQS

- SSM

- STS

- SWF

普段からテストコード作成をクセづけておき、テストコードがオールグリーンになれば開発完了になる感じになっていけばなと思いました。

まずはそのとっかかりにでも。