如何修补异步类方法?

2024-09-28 23:40:42 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在处理以下问题,我有一个类,一个异步方法,我想模拟补丁:

class ExampleClass:
    async def asy_method(self, param):
        return await some_coroutine(self, param)

example_instance = ExampleClass()

我只想专门修补像

^{pr2}$

通常我会用

mocker.patch('ExampleClass.asy_method', new_callable=AsyncMock)

其中mocker是pytest mock插件fixture,AsyncMock具有以下形式

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

这会给我一个模拟对象,它的行为类似于随叫随到的协同程序。 问题是,我想访问传递给方法的self属性。self只有在设置 autospec=True(另请参见Python Doc on patching unbound methods),它不能与new_callable一起使用。在

有人知道如何解决这个问题吗?在


Tags: 方法selfnewasyncreturnparamdefmock
1条回答
网友
1楼 · 发布于 2024-09-28 23:40:42

事实上,你不能把自动选择和新的可调用代码混合在一起。相反,自动指定方法,但随后替换side_effect属性,给它一个AsyncMock()实例:

from unittest import mock


def configure_coroutine_mock(mock_function, klass=AsyncMock):
    """Make an autospecced async function return a coroutine mock"""
    mock_function.side_effect = AsyncMock()
    # mark the side effect as a child of the original mock object
    # so transitive access is recorded on the parent mock too. This is 
    # what .return_value does normally
    mock._check_and_set_parent(
        mock_function.mock, mock_function.side_effect,
        None, '()')
    return mock_asy_method.side_effect


with mocker.patch('ExampleClass.asy_method', autospec=True) as mock_asy_method:
    configure_coroutine_mock(mock_asy_method)

因为AsyncMock()是一个可调用的对象,所以每当mock_asy_method被调用时,它都会被称为,并将参数传递给该对象。然后使用该调用的结果从mock_asy_method()返回:

^{pr2}$

如您所见,self参数和参数被记录在调用中,因为mock_asy_method是一个正确指定的函数。在

当然,只有在实际等待返回的AsyncMock()调用结果时,我们才会看到记录的调用:

>>> with mock.patch('__main__.ExampleClass.asy_method', autospec=True) as mock_asy_method:
...     configure_coroutine_mock(mock_asy_method)
...     loop = asyncio.get_event_loop()
...     coro = example_instance.asy_method('foo')
...     loop.run_until_complete(coro)
...     print(mock_asy_method.mock_calls)
...     
<AsyncMock name='asy_method()' id='4564408920'>
<AsyncMock name='asy_method()()' id='4564999360'>    
[call(<__main__.ExampleClass object at 0x10ffac1d0>, 'foo'),
 call()(<__main__.ExampleClass object at 0x10ffac1d0>, 'foo')]

相关问题 更多 >