💭
boto3で特定のメソッドをmockする
やりたいこと
Pythonのユニットテストで、boto3クライアントの特定メソッド(だけ)をモックしたいときがあります。こちらのstackoverflowに良さそうのやり方があったのでメモ。解はいろいろありそうですが、そのうち2つに関して書きます。(※motoは使わない)
方法1. botocoreのstubを使う
boto3のドキュメントよりコードをコピペ
import datetime
import botocore.session
from botocore.stub import Stubber
s3 = botocore.session.get_session().create_client('s3')
response = {
"Owner": {
"ID": "foo",
"DisplayName": "bar"
},
"Buckets": [{
"CreationDate": datetime.datetime(2016, 1, 20, 22, 9),
"Name": "baz"
}]
}
with Stubber(s3) as stubber:
stubber.add_response('list_buckets', response, {})
service_response = s3.list_buckets()
assert service_response == response
- s3の
list_buckets
をmockしている例 - with句でなくても可能。ない場合は
stubber.activate()
が必要 - 上記では空の
{}
になっておりs3.list_buckets()
は引数なし。expected_params = {'Bucket': 'test-bucket'}
をstubber.add_response
に与えると、その値のときだけmockする。expected_params = {'Bucket': ANY}
とすると、s3.list_buckets()
に何が入ってもよいことになる
expected_params = {'Bucket': ANY}
stubber.add_response('list_objects', response, expected_params)
with stubber:
service_response = s3.list_objects(Bucket='test-bucket')
assert service_response == response
方法2. boto3の_make_api_callを差し替える
上記Stackoverflowで紹介されている方法です。同じ人が別の質問に書いている回答もあります。コードは前者からコピペ。
import botocore
from botocore.exceptions import ClientError
from mock import patch
import boto3
orig = botocore.client.BaseClient._make_api_call
def mock_make_api_call(self, operation_name, kwarg):
if operation_name == 'UploadPartCopy':
parsed_response = {'Error': {'Code': '500', 'Message': 'Error Uploading'}}
raise ClientError(parsed_response, operation_name)
return orig(self, operation_name, kwarg)
with patch('botocore.client.BaseClient._make_api_call', new=mock_make_api_call):
client = boto3.client('s3')
# Should return actual result
o = client.get_object(Bucket='my-bucket', Key='my-key')
# Should return mocked exception
e = client.upload_part_copy()
- s3の
upload_part_copy
をmockしている例 - boto3.clientが、
_make_api_call
というメソッドを使ってAPIを呼んでいることに注目して、その部分を差し替える -
def mock_make_api_call(self, operation_name, kwarg):
で、特定の操作のときにだけ差し替えます(ここではoperation_name == 'UploadPartCopy'
のときraise ClientError
に差し替え)。それ以外は、orig()を返すのでそのままになる-
UploadPartCopy
というCamelCaseでの書き方を探す場合は、例えばこのAWSドキュメントを参照
-
- with patchを使って
_make_api_call
をmock_make_api_call
でモックすると、client.upload_part_copy()
のときは、operation_name == 'UploadPartCopy'
がTrueなのでモックされる
まとめ
- boto3クライアントの特定メソッドをmockする方法について書きました
- どちらが良いかというのはケースバイケースですが、個人的に解りやすかったので方法2を使いました
Discussion