猿问

如何修补异步类方法?

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


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。


有谁知道如何解决这个问题?


慕标琳琳
浏览 134回答 1
1回答

眼眸繁星

确实,您不能混合使用自动指定和新的可调用项。相反,可以自动指定方法,然后替换side_effect属性,并为其指定一个AsyncMock()实例:from unittest import mockdef configure_coroutine_mock(mock_function, klass=AsyncMock):&nbsp; &nbsp; """Make an autospecced async function return a coroutine mock"""&nbsp; &nbsp; mock_function.side_effect = AsyncMock()&nbsp; &nbsp; # mark the side effect as a child of the original mock object&nbsp; &nbsp; # so transitive access is recorded on the parent mock too. This is&nbsp;&nbsp; &nbsp; # what .return_value does normally&nbsp; &nbsp; mock._check_and_set_parent(&nbsp; &nbsp; &nbsp; &nbsp; mock_function.mock, mock_function.side_effect,&nbsp; &nbsp; &nbsp; &nbsp; None, '()')&nbsp; &nbsp; return mock_asy_method.side_effectwith mocker.patch('ExampleClass.asy_method', autospec=True) as mock_asy_method:&nbsp; &nbsp; configure_coroutine_mock(mock_asy_method)因为AsyncMock()是可调用的对象,所以每次mock_asy_method调用都会调用,并将参数传递给该对象。然后,该调用的结果用于从返回mock_asy_method():>>> from unittest import mock>>> class ExampleClass:...&nbsp; &nbsp; &nbsp;async def asy_method(self, param):...&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return await some_coroutine(self, param)...>>> example_instance = ExampleClass()>>> with mock.patch('__main__.ExampleClass.asy_method', autospec=True) as mock_asy_method:...&nbsp; &nbsp; &nbsp;configure_coroutine_mock(mock_asy_method)...&nbsp; &nbsp; &nbsp;print(example_instance.asy_method('foo'))&nbsp; # call to patched class coroutine...&nbsp; &nbsp; &nbsp;print(mock_asy_method.mock_calls)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # 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:...&nbsp; &nbsp; &nbsp;configure_coroutine_mock(mock_asy_method)...&nbsp; &nbsp; &nbsp;loop = asyncio.get_event_loop()...&nbsp; &nbsp; &nbsp;coro = example_instance.asy_method('foo')...&nbsp; &nbsp; &nbsp;loop.run_until_complete(coro)...&nbsp; &nbsp; &nbsp;print(mock_asy_method.mock_calls)...&nbsp; &nbsp; &nbsp;<AsyncMock name='asy_method()' id='4564408920'><AsyncMock name='asy_method()()' id='4564999360'>&nbsp; &nbsp;&nbsp;[call(<__main__.ExampleClass object at 0x10ffac1d0>, 'foo'),&nbsp;call()(<__main__.ExampleClass object at 0x10ffac1d0>, 'foo')]
随时随地看视频慕课网APP

相关分类

Python
我要回答