为了账号安全,请及时绑定邮箱和手机立即绑定

如何修补异步类方法?

如何修补异步类方法?

慕标琳琳 2021-04-02 10:11:22
我正在处理以下问题,我有一个类,我想模拟其补丁的异步方法:class ExampleClass:    async def asy_method(self, param):        return await some_coroutine(self, param)example_instance = ExampleClass()我只想打补丁await example_instance.asy_method('test_param')通常我会用mocker.patch('ExampleClass.asy_method', new_callable=AsyncMock)其中,mocker是pytest-mock插件的固定装置,而AsyncMock具有以下形式class AsyncMock(mock.MagicMock):    async def __call__(self, *args, **kwargs):         return super(AsyncMock, self).__call__(*args, **kwargs)这会给我一个Mock对象,它在调用时的行为像协程。问题是,我想访问self传递给方法的属性。self仅在您进行设置的情况下才传递给模拟对象 autospec=True(另请参阅Python Doc,了解如何修补未绑定的方法),您不能与一起使用new_callable。有谁知道如何解决这个问题?
查看完整描述

1 回答

?
眼眸繁星

TA贡献1873条经验 获得超9个赞

确实,您不能混合使用自动指定和新的可调用项。相反,可以自动指定方法,然后替换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():


>>> from unittest import mock

>>> class ExampleClass:

...     async def asy_method(self, param):

...         return await some_coroutine(self, param)

...

>>> example_instance = ExampleClass()

>>> with mock.patch('__main__.ExampleClass.asy_method', autospec=True) as mock_asy_method:

...     configure_coroutine_mock(mock_asy_method)

...     print(example_instance.asy_method('foo'))  # call to patched class coroutine

...     print(mock_asy_method.mock_calls)          # calls are recorded

...

<AsyncMock name='asy_method()' id='4563887496'>

<coroutine object AsyncMock.__call__ at 0x1100780f8>

[call(<__main__.ExampleClass object at 0x10ffac1d0>, 'foo')]

如您所见,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')]


查看完整回答
反对 回复 2021-04-13
  • 1 回答
  • 0 关注
  • 133 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号