Mocking 使用上下文管理器测试异步协同路由

Mocking 使用上下文管理器测试异步协同路由,mocking,python-asyncio,python-3.7,python-unittest,asynctest,Mocking,Python Asyncio,Python 3.7,Python Unittest,Asynctest,我一直在尝试在Python3.7中通过aiobotocore测试上下文管理的异步协同路由。我一直在使用asynctest包来获取包含的MagicMock,它具有\uuuu aenter\uuuu和\uuuu aexit\uuuu的神奇方法,以及一个自定义的模拟工厂,该工厂返回一个MagicMock对象作为可等待的协同程序的结果,但我在上下文管理器中遇到了协同程序的问题。我试图模拟的函数: from aiologger import Logger import aiobotocore asyn

我一直在尝试在Python3.7中通过aiobotocore测试上下文管理的异步协同路由。我一直在使用asynctest包来获取包含的MagicMock,它具有
\uuuu aenter\uuuu
\uuuu aexit\uuuu
的神奇方法,以及一个自定义的模拟工厂,该工厂返回一个MagicMock对象作为可等待的协同程序的结果,但我在上下文管理器中遇到了协同程序的问题。我试图模拟的函数:

from aiologger import Logger
import aiobotocore


async def delete_file(bucket, key, alogger):
    await alogger.info(f'deleting file {key}')
    session = aiobotocore.get_session()
    async with session.create_client('s3', use_ssl=False) as s3:
        await s3.delete_object(
            Bucket=bucket,
            Key=key)
这是在代码后面的输入参数中调用的,我的测试代码是:

import asyncio
from src import main
from unittest import TestCase, mock
from asynctest.mock import CoroutineMock, MagicMock as AsyncMagicMock

 class AsyncMockCall(mock.MagicMock):
    async def __call__(self, *args, **kwargs):
        return super().__call__(*args, **kwargs)

class TestMain(TestCase):

    @mock.patch('src.main.aiobotocore.get_session', new_callable=AsyncMagicMock)
    @mock.patch('src.main.Logger', new_callable=AsyncMockCall)
    def test_delete_file(self, alogger, botomock):
        loop = asyncio.get_event_loop()
        loop.run_until_complete(main.delete_file('test_bucket',
                                                'test_key.csv',
                                                alogger))
然而,当我运行它时,我得到了以下错误消息:

____________________________________________________________________________ TestMain.test_delete_file ____________________________________________________________________________

self = <tests.test_main.TestMain testMethod=test_delete_file>, alogger = <AsyncMockCall name='Logger' id='4480486312'>, botomock = <MagicMock name='get_session' id='4480486144'>

    @mock.patch('src.main.aiobotocore.get_session', new_callable=AsyncMagicMock)
    @mock.patch('src.main.Logger', new_callable=AsyncMockCall)
    def test_delete_file(self, alogger, botomock):
        loop = asyncio.get_event_loop()
        loop.run_until_complete(main.delete_file('test_bucket',
                                                'test_key.csv',
>                                               alogger))

tests/test_main.py:21: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/base_events.py:584: in run_until_complete
    return future.result()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

bucket = 'test_bucket', key = 'test_key.csv', alogger = <AsyncMockCall name='Logger' id='4480486312'>

    async def delete_file(bucket, key, alogger):
        await alogger.info(f'deleting file {key}')
        session = aiobotocore.get_session()
        async with session.create_client('s3', use_ssl=False) as s3:
            await s3.delete_object(
                Bucket=bucket,
>               Key=key)
E           TypeError: object MagicMock can't be used in 'await' expression

src/main.py:20: TypeError
============================================================================= short test summary info =============================================================================
FAILED tests/test_main.py::TestMain::test_delete_file - TypeError: object MagicMock can't be used in 'await' expression
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu____________________________________________________________________________
self=,alogger=,botomock=
@mock.patch('src.main.aiobotocore.get\u session',new\u callable=AsyncMagicMock)
@补丁('src.main.Logger',new_callable=AsyncMockCall)
def test_delete_文件(self、alogger、botomock):
loop=asyncio.get\u event\u loop()
循环。运行_直到_完成(main.delete_文件('test_bucket'),
“test_key.csv”,
>阿洛格)
测试/测试主管道py:21:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/base\u events.py:584:运行直到完成
返回future.result()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
bucket='test_bucket',key='test_key.csv',alogger=
异步def delete_文件(bucket、key、alogger):
wait alogger.info(f'deleting file{key}')
session=aiobotocore.get_session()
与会话异步。创建\u客户端('s3',使用\u ssl=False)作为s3:
等待s3.delete_对象(
桶=桶,
>钥匙=钥匙)
E TypeError:对象MagicMock不能用于'await'表达式
src/main.py:20:TypeError
=================================================================================================================================================================================简短测试摘要信息=============================================================================
失败的测试/test_main.py::TestMain::test_delete_文件-类型错误:无法在“await”表达式中使用对象MagicMock

在我看来,我需要asynctest magicmock来处理上下文管理器,但是我需要定制的mock来返回一个协同路由。我知道有一个带有asynctest的协同例程,但我无法让它在这种情况下工作,我该如何解决这个问题?

因此从其他答案来看,我似乎需要用协同例程模拟特定的delete\u对象方法,而我让它工作的问题是,aiobotocore使用AioSession作为get会话的类,以下代码有效:

import asyncio
from src import main
from unittest import TestCase, mock
from asynctest.mock import CoroutineMock, MagicMock as AsyncMagicMock

class AsyncMockCall(mock.MagicMock):
    async def __call__(self, *args, **kwargs):
        return super().__call__(*args, **kwargs)

class TestMain(TestCase):

    @mock.patch('src.main.aiobotocore.AioSession.create_client', new_callable=AsyncMagicMock)
    @mock.patch('src.main.Logger', new_callable=AsyncMockCall)
    def test_delete_file(self, alogger, botomock):
        loop = asyncio.get_event_loop()
        botomock.return_value.__aenter__.return_value.delete_object = CoroutineMock(return_value=[])
        loop.run_until_complete(main.delete_file('test_bucket',
                                                'test_key.csv',
                                                alogger)) 

具体还有什么其他答案?