Burlándose del método cliente boto3 S3 Python


Estoy tratando de burlarme de un método singluar del objeto cliente boto3 s3 para lanzar y exception. 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 realizando 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

Segundo intento

Después de mirar el botocore.client.py código fuente Encontré que es hacer algo inteligente y el método upload_part_copy no existe. Encontré que parece llamar BaseClient._make_api_call en su 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?

Author: ptimson, 2016-05-10

4 answers

Botocore tiene un stubber de cliente que puede usar para este propósito: docs.

Aquí hay un ejemplo de poner un error:

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()

Aquí hay un ejemplo de poner una respuesta normal. Además, el stubber ahora se puede usar en un contexto. Es importante tener en cuenta que el stubber verificará, en la medida de lo posible, que su respuesta proporcionada coincida con lo que el servicio realmente devolverá. Esto no es perfecto, pero te protegerá de insertar tonterías totales respuesta.

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
 43
Author: Jordon Phillips,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-03 18:13:23

Tan pronto como publiqué aquí me las arreglé para llegar a 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 usando el botocore .stub.Stubber clase. Mientras que una solución más limpia yo era incapaz de simular operaciones específicas.

 10
Author: ptimson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:13

Aquí hay un ejemplo de un simple unittest de python que se puede usar para falsificar client = boto3.cliente ('ec2') llamada a la api...

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'
}

Espero que eso ayude.

 5
Author: Aidan Melen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-09 13:40:49

¿Qué tal simplemente usar moto?

Viene con un decorador muy práctico :

from moto import mock_s3

@mock_s3
def test_my_model_save():
    pass
 1
Author: wikier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-07 21:09:35