putobject - Burlándose de boto3 S3 cliente método Python
write a file to s3 python (4)
¿Qué hay de simplemente usar moto ?
Viene con un decorator muy práctico:
from moto import mock_s3
@mock_s3
def test_my_model_save():
pass
Estoy tratando de burlarme de un método singular del objeto cliente de boto3 s3 para lanzarlo y una excepción. Pero necesito todos los otros métodos para que esta clase funcione normalmente.
Esto es para que pueda probar una prueba de excepción singular cuando se produce un error al realizar una upload_part_copy
1er intento
import boto3
from mock import patch
with patch(''botocore.client.S3.upload_part_copy'', side_effect=Exception(''Error Uploading'')) as mock:
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()
Sin embargo, esto da el siguiente error:
ImportError: No module named S3
2do intento
Después de mirar el código fuente de botocore.client.py, descubrí que está haciendo algo inteligente y que el método upload_part_copy
no existe. Encontré que parece llamar a BaseClient._make_api_call
en BaseClient._make_api_call
lugar, así que traté de burlarme de eso
import boto3
from mock import patch
with patch(''botocore.client.BaseClient._make_api_call'', side_effect=Exception(''Error Uploading'')) as mock:
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()
Esto lanza una excepción pero lanza una excepción ... pero en el get_object
que quiero evitar.
¿Alguna idea sobre cómo solo puedo lanzar la excepción en el método upload_part_copy
?
Aquí hay un ejemplo de una prueba de unidad de python simple que se puede usar para falsificar la llamada api client = boto3.client (''ec2'') ...
import boto3
class MyAWSModule():
def __init__(self):
client = boto3.client(''ec2'')
tags = client.describe_tags(DryRun=False)
class TestMyAWSModule(unittest.TestCase):
@mock.patch("boto3.client.get_tags")
@mock.patch("boto3.client")
def test_open_file_with_existing_file(self, mock_boto_client, mock_describe_tags):
mock_boto_client.return_value = mock_get_tags_response
my_aws_module = MyAWSModule()
mock_boto_client.assert_call_once(''ec2'')
mock_describe_tags.assert_call_once_with(DryRun=False)
mock_get_tags_response = {
''Tags'': [
{
''ResourceId'': ''string'',
''ResourceType'': ''customer-gateway'',
''Key'': ''string'',
''Value'': ''string''
},
],
''NextToken'': ''string''
}
Esperemos que eso ayude.
Botocore tiene un cliente que puedes usar para este propósito: docs .
Aquí hay un ejemplo de poner un error en:
import boto3
from botocore.stub import Stubber
client = boto3.client(''s3'')
stubber = Stubber(client)
stubber.add_client_error(''upload_part_copy'')
stubber.activate()
# Will raise a ClientError
client.upload_part_copy()
Este es un ejemplo de cómo poner una respuesta normal. Además, ahora se puede usar el stubber en un contexto. Es importante tener en cuenta que el rastreador verificará, en la medida de lo posible, que su respuesta proporcionada coincida con lo que realmente devolverá el servicio. Esto no es perfecto, pero lo protegerá de la inserción de respuestas sin sentido.
import boto3
from botocore.stub import Stubber
client = boto3.client(''s3'')
stubber = Stubber(client)
list_buckets_response = {
"Owner": {
"DisplayName": "name",
"ID": "EXAMPLE123"
},
"Buckets": [{
"CreationDate": "2016-05-25T16:55:48.000Z",
"Name": "foo"
}]
}
expected_params = {}
stubber.add_response(''list_buckets'', list_buckets_response, expected_params)
with stubber:
response = client.list_buckets()
assert response == list_buckets_response
Tan pronto como publiqué aquí pude encontrar una solución. Aquí está la esperanza que ayuda :)
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()
Jordan Philips también publicó una gran solución utilizando la clase docs . Mientras que una solución más limpia no podía simular operaciones específicas.