首页 > 解决方案 > 单元测试从 s3 下载 json 文件的函数

问题描述

我有一个功能如下:

def read_json(bucket, key):
    """

    :param bucket:
    :param key:
    :return:
    """
    s3 = boto3.resource('s3')
    content_object = S3.Object(bucket, key)
    file_content = content_object.get()['Body'].read().decode('utf-8')
    json_content = json.loads(file_content)
    return json_content

我正在测试这个功能,如下所示:

@mock.patch('boto3.resource')
def test_read_json(mock_resource):

    mock_resource.Object.return_value.return_value = '{ "key":"value", ' \
                                              '"key_1":value_1, ' \
                                              '"key_2":"value_2"}'
    json = helpers.read_json('bucket', 'key')
    mock_resource.assert_called_once_with('s3')
    tools.assert_is_instance(json, 'json')

TypeError:JSON 对象必须是 str、bytes 或 bytearray,而不是 MagicMock

有什么想法我在这里可能做错了吗?

标签: pythonpython-3.xnose

解决方案


它真的不漂亮,但创建一些模拟类将解决问题:

class MockBody():
    def read(self):
        return '{ "key": "value", ' \
               '"key_1": "value_1", ' \
               '"key_2": "value_2" }'.encode('utf-8')


class MockBoto3Resource():
    class Object():
        def __init__(self, bucket, key):
            pass
        def get(self):
            return {'Body': MockBody()}

然后像这样在你的测试中使用它:

@mock.patch('boto3.resource')
def test_read_json(mock_resource):
    mock_resource.return_value = MockBoto3Resource
    [...]

您可能想看一下 Stubber ( https://botocore.amazonaws.com/v1/documentation/api/latest/reference/stubber.html ),我个人从未使用过它,但您可能可以通过使用使其更优雅botocore.stub.Stubber.


推荐阅读