ã¯ããã«
Amazon S3ãªã©ã®ã¯ã©ãŠããµãŒãã¹ã䜿çšããã¢ããªã±ãŒã·ã§ã³ããã¹ãããå Žåã
å®éã®ã¯ã©ãŠããªãœãŒã¹ã䜿ããã«ããŒã«ã«ç°å¢ã§ãã¹ããè¡ãããããšããããŸãã
ãã®ãããªå Žåãpytestãšpytest-mockã䜿çšããŠãå€éšãµãŒãã¹ã®åŒã³åºããã¢ãã¯åããããšãã§ããŸãã
ä»åã¯pytestãšmockã䜿çšããŠAmazon S3ã®put_objectæäœãããŒã«ã«ç°å¢ã§ãã¹ãããæ¹æ³ã«ã€ããŠèª¬æããŸãã
ã¢ãã¯ãšã¯
ç°¡åã«èšãã°ããæ¬ç©ã®ã³ã³ããŒãã³ãã®ä»£ããã«ããã¹ãçšã®åœç©ã䜿ã£ãŠåäœã確èªãããããšã§ãã
ã¢ãã¯ã®åºæ¬çãªåäœ
ãŸããpytestãšmockã®åºæ¬çãªäœ¿ãæ¹ãèŠãŠãããŸãã
# ã¢ãã¯ã®åºæ¬çãªäŸ
def test_mock_example(mocker):
# 颿°ãã¡ãœãããã¢ãã¯å
mock_function = mocker.patch("module.function_name")
# ã¢ãã¯åãã颿°ã®æ»ãå€ãèšå®
mock_function.return_value = "mocked_result"
# ã¢ãã¯åãã颿°ã®åŒã³åºã
result = mock_function()
# ã¢ãµãŒã·ã§ã³
assert result == "mocked_result"
# 颿°ãåŒã³åºãããããšã確èª
mock_function.assert_called_once()
ãã®ã³ãŒãã詳ãã説æãããšïŒ
1ïŒmocker㯠pytest-mock ãã©ã°ã€ã³ãæäŸãããã£ã¯ã¹ãã£ã§ãã
Pythonã®æšæºã©ã€ãã©ãªã§ãã unittest.mock ã®ã©ãããŒãšããŠæ©èœãã
ãã¹ãå
ã§ã¢ãã¯ãªããžã§ã¯ããç°¡åã«äœæã§ããããã«ããŸãã
2ïŒmocker.patch("module.function_name")ã®åŒæ°ã¯ãã¢ãã¯åããã颿°ãã¯ã©ã¹ã®
ãã€ã³ããŒããã¹ããæååã§æå®ããŸãã
åŒæ°ã®äŸïŒ
â "os.path.exists" â osã¢ãžã¥ãŒã«ã®path.exists颿°ãã¢ãã¯
â "myapp.models.User" â myappããã±ãŒãžã®modelsã¢ãžã¥ãŒã«ã«ããUserã¯ã©ã¹ãã¢ãã¯
mocker.patchã¯æå®ããããã¹ã®ãªããžã§ã¯ããäžæçã«çœ®ãæãããã¹ãçµäºåŸã«èªåçã«å
ã«æ»ããŸãã
3ïŒmock_function.return_value = "mocked_result" ã§ã¯ãã¢ãã¯åãã颿°ãåŒã³åºããããšãã«
è¿ãå€ãèšå®ããŠããŸãã
4ïŒãã¹ãå
ã§ã¯ assert ã䜿ã£ãŠãã¢ãã¯é¢æ°ã®æåãåŒã³åºãå±¥æŽãæ€èšŒããŠããŸãã
Amazon S3ã®put_objectæäœãã¢ãã¯åããŠãã¹ããã
ããã§ã¯ãæ¬é¡ã®Amazon S3ã®put_objectæäœãã¢ãã¯åããŠãã¹ãããã³ãŒããèŠãŠãããŸãã
ãã¹ã察象ã®ã³ãŒã
ãŸãããã¹ã察象ãšãªãS3ã«ãã¡ã€ã«ãã¢ããããŒããã颿°ãå®çŸ©ããŸãã
# s3_upload.py
import boto3
from botocore.exceptions import ClientError
def upload_file_to_s3(file_path, bucket_name, object_name=None):
"""
S3ãã±ããã«ãã¡ã€ã«ãã¢ããããŒããã颿°
:param file_path: ã¢ããããŒããããã¡ã€ã«ã®ãã¹
:param bucket_name: ã¢ããããŒãå
ã®S3ãã±ããå
:param object_name: S3ãªããžã§ã¯ãåïŒæå®ããªãå Žåã¯ãã¡ã€ã«åã䜿çšãããïŒ
:return: ã¢ããããŒããæåãããã©ããã®ããŒã«å€
"""
# ãªããžã§ã¯ãåãæå®ãããŠããªãå Žåã¯ããã¡ã€ã«åã䜿çš
if object_name is None:
object_name = file_path.split("/")[-1]
# S3ã¯ã©ã€ã¢ã³ããäœæ
s3_client = boto3.client("s3")
try:
# ãã¡ã€ã«ãS3ã«ã¢ããããŒã
s3_client.put_object(
Body=open(file_path, "rb"), Bucket=bucket_name, Key=object_name
)
return True
except ClientError as e:
print(f"ãšã©ãŒãçºçããŸãã: {e}")
return False
ãã¹ãã³ãŒã
次ã«ããã®é¢æ°ããã¹ãããã³ãŒããäœæããŸããS3ãžã®ã¢ã¯ã»ã¹ãã¢ãã¯åãããã
boto3ã®ã¯ã©ã€ã¢ã³ããã¢ãã¯åããŸããç°¡æçã«æåãšå€±æããã¹ãããã±ãŒã¹ã ãçšæããŸããã
# test_s3_upload.py
import os
from unittest.mock import mock_open
import pytest
from s3_upload import upload_file_to_s3
def test_upload_file_to_s3_success(mocker):
"""S3ã¢ããããŒããæåããã±ãŒã¹ã®ãã¹ã"""
# ãã¡ã€ã«ã®ã¢ãã¯
mock_file = mock_open(read_data=b"test file content")
mocker.patch("builtins.open", mock_file)
# S3ã¯ã©ã€ã¢ã³ãã®ã¢ãã¯
mock_s3_client = mocker.Mock()
mocker.patch("boto3.client", return_value=mock_s3_client)
# ãã¹ãå®è¡
result = upload_file_to_s3("dummy_file.txt", "test-bucket", "test-key.txt")
# ã¢ãµãŒã·ã§ã³
assert result is True
# S3ã¯ã©ã€ã¢ã³ããæ£ãããã©ã¡ãŒã¿ã§åŒã³åºãããããšã確èª
mock_s3_client.put_object.assert_called_once()
_, kwargs = mock_s3_client.put_object.call_args
assert kwargs["Bucket"] == "test-bucket"
assert kwargs["Key"] == "test-key.txt"
# Bodyå
å®¹ã®æ€èšŒã远å
assert kwargs["Body"].read() == b"test file content"
# ãã¡ã€ã«ãéãããããšã確èª
mock_file.assert_called_once_with("dummy_file.txt", "rb")
def test_upload_file_to_s3_fail(mocker):
"""S3ã¢ããããŒãã倱æããã±ãŒã¹ã®ãã¹ã"""
# ãã¡ã€ã«ã®ã¢ãã¯
mock_file = mock_open(read_data=b"test file content")
mocker.patch("builtins.open", mock_file)
# boto3.clientã®ã¢ãã¯
mock_s3_client = mocker.Mock()
# put_objectã¡ãœãããäŸå€ãæããããã«èšå®
from botocore.exceptions import ClientError
mock_s3_client.put_object.side_effect = ClientError(
{"Error": {"Code": "AccessDenied", "Message": "Access Denied"}}, "put_object"
)
mocker.patch("boto3.client", return_value=mock_s3_client)
# ããªã³ãã®ã¢ãã¯ïŒãšã©ãŒã¡ãã»ãŒãžã®åºåããã£ããã£ããªãããïŒ
mocker.patch("builtins.print")
# ãã¹ãå®è¡
result = upload_file_to_s3("dummy_file.txt", "test-bucket")
# ã¢ãµãŒã·ã§ã³
assert result is False
# put_objectãåŒã³åºãããããšã確èª
mock_s3_client.put_object.assert_called_once()
äžèšã³ãŒãã®ãã€ã³ã
1ïŒãã¡ã€ã«ã®ã¢ãã¯å:
mock_openãšmocker.patch("builtins.open", mock_file)ã䜿çšããŠããã¡ã€ã«ã®ãªãŒãã³æäœã
ã¢ãã¯åããŠããŸããå®éã®ãã¡ã€ã«ãäœæããå¿
èŠã¯ãããŸããã
mock_openã®åŒæ°read_dataã¯ãã¢ãã¯åããããã¡ã€ã«ãªããžã§ã¯ãããèªã¿èŸŒãŸããããŒã¿ã
æå®ããŸããä»åã¯b"test file content"ãšãããã€ããªããŒã¿ãèšå®ããŠããããããã¡ã€ã«ã
éããŠread()ã¡ãœãããåŒã³åºããšããã®ããŒã¿ãè¿ãããŸãã
ããã«ãããå®éã®ãã¡ã€ã«ã·ã¹ãã ã«ã¢ã¯ã»ã¹ããã«ãã¡ã€ã«æäœãã·ãã¥ã¬ãŒãã§ããŸãã
2ïŒboto3.clientã®ã¢ãã¯å:
mocker.patch("boto3.client", return_value=mock_s3_client)ã䜿çšããŠãboto3ã®S3ã¯ã©ã€ã¢ã³ãã
ã¢ãã¯åããŠããŸããããã«ãããå®éã®AWSãµãŒãã¹ã«ã¢ã¯ã»ã¹ããããšãªããã¹ããã§ããŸãã
ãã®éšåã§ã¯ãboto3.clientã®åŒã³åºããåžžã«mock_s3_clientãªããžã§ã¯ããè¿ãããã«èšå®ããŠããŸãã
mock_s3_clientã¯Mockãªããžã§ã¯ãã§ãå
šãŠã®ã¡ãœããåŒã³åºããèšé²ããæå®ãããæ»ãå€ãè¿ã
ããšãã§ããŸãã
3ïŒã¢ãµãŒã·ã§ã³:
mock_s3_client.put_object.assert_called_once()ãmock_file.assert_called_once_with(...)ã
䜿çšããŠãã¢ãã¯åãããªããžã§ã¯ããæåŸ
éãã«åŒã³åºãããããšã確èªããŠããŸãã
ãããã®ã¢ãµãŒã·ã§ã³ã¯ãã¢ãã¯ãªããžã§ã¯ãã®åŒã³åºãåæ°ãæž¡ããããã©ã¡ãŒã¿ãæ€èšŒããŸãã
äŸãã°ãassert_called_once()ã¯ã¡ãœãããæ£ç¢ºã«1åã ãåŒã³åºãããããšã確èªãã
assert_called_once_with()ã¯ç¹å®ã®åŒæ°ã§1ååŒã³åºãããããšãæ€èšŒããŸãã
4ïŒãã©ã¡ãŒã¿å
å®¹ã®æ€èšŒ:
assert kwargs["Body"].read() == b"test file content"ã䜿çšããŠãS3ã«ã¢ããããŒãããã
ãã¡ã€ã«ã®å
容ãæåŸ
éãã§ããããšã確èªããŠããŸãã
ãã®æ€èšŒã§ã¯ãS3ã®put_objectã¡ãœããã«æž¡ãããBodyåŒæ°ïŒãã¡ã€ã«ãªããžã§ã¯ãïŒããå®éã«
èªã¿èŸŒãã ããŒã¿ããæåŸ
ããå
容ãšäžèŽããã確èªããŠããŸããããã«ãããåã«ã¡ãœããã
åŒã³åºãããã ãã§ãªããæ£ããããŒã¿ãã¢ããããŒããããããšãæ€èšŒã§ããŸãã
5ïŒäŸå€ã®ã¢ãã¯å:
倱æã±ãŒã¹ã®ãã¹ãã§ã¯ãmock_s3_client.put_object.side_effect = ClientErrorã䜿çšããŠã
S3ã¯ã©ã€ã¢ã³ããäŸå€ãæããããã«ã¢ãã¯åããŠããŸãã
side_effectãèšå®ããããšã§ãã¡ãœãããåŒã³åºããããšãã«æå®ããäŸå€ãçºçãããããšã
ã§ããŸãããã®äŸã§ã¯ãAWSã®ClientErroräŸå€ãçºçãããããšã§ãS3ã¢ããããŒãã®å€±æã·ããªãªã
ã·ãã¥ã¬ãŒãããŠããŸããããã«ããããšã©ãŒåŠçã³ãŒãã®ãã¹ããå¯èœã«ãªããŸãã
ãã¹ãã®å®è¡æ¹æ³
äžèšã®ãã¹ããå®è¡ããã«ã¯ããŸãå¿ èŠãªããã±ãŒãžãã€ã³ã¹ããŒã«ããŸãã
# å¿ èŠãªããã±ãŒãžã®ã€ã³ã¹ããŒã« pip install pytest pytest-mock boto3
ãã®åŸã以äžã®ã³ãã³ãã§ãã¹ããå®è¡ããŸãã
pytest test_s3_upload.py -v
ãŸãšã
pytestãšmockã䜿çšããããšã§ãAmazon S3ãªã©ã®å€éšãµãŒãã¹ã䜿çšããã³ãŒããå®éã®ãµãŒãã¹ã«
ã¢ã¯ã»ã¹ããããšãªãããŒã«ã«ç°å¢ã§ãã¹ãããããšãã§ããŸãããã®ã¢ãããŒãã«ã¯ä»¥äžã®ã¡ãªããããããŸãã
1ïŒãã¹ãã®å®è¡ãéããªãïŒå®éã®ãããã¯ãŒã¯éä¿¡ãçºçããªãããïŒ
2ïŒã³ã¹ããåæžã§ããïŒAWSã®æéãçºçããªãïŒ
3ïŒãã¹ãç°å¢ã®å¶åŸ¡ã容æã«ãªãïŒãšã©ãŒã±ãŒã¹ã®ã·ãã¥ã¬ãŒã·ã§ã³ãªã©ïŒ
4ïŒCI/CDãã€ãã©ã€ã³ã§ã®å®è¡ãç°¡åã«ãªãïŒèªèšŒæ
å ±ãäžèŠïŒ
ã¢ãã¯ã广çã«æŽ»çšããããšã§ãããå
ç¢ã§ä¿¡é Œæ§ã®é«ãã³ãŒããéçºããããšãã§ããŸãã
ãã ããæçµçã«ã¯å®éã®ç°å¢ã§çµ±åãã¹ãã宿œããã¢ãã¯åãããéšåãæ¬çªç°å¢ã§ãæåŸ
éãã«
åäœããããšã確èªããããšã倧åã§ãã