sha*_*hia 6 python unit-testing asynchronous mocking
当我尝试使用MagicMock模拟单元测试中的异步函数时,出现了以下异常:
TypeError:对象MagicMock不能在'await'表达式中使用
带有如下示例代码:
# source code
class Service:
async def compute(self, x):
return x
class App:
def __init__(self):
self.service = Service()
async def handle(self, x):
return await self.service.compute(x)
# test code
import asyncio
import unittest
from unittest.mock import patch
class TestApp(unittest.TestCase):
@patch('__main__.Service')
def test_handle(self, mock):
loop = asyncio.get_event_loop()
app = App()
res = loop.run_until_complete(app.handle('foo'))
app.service.compute.assert_called_with("foo")
if __name__ == '__main__':
unittest.main()
Run Code Online (Sandbox Code Playgroud)
我应该如何使用内置的python3库修复它?
z0r*_*z0r 11
您可以获得模拟以返回可以使用Future等待的对象。以下是一个pytest测试用例,但应该可以使用unittest 进行类似的操作。
async def test_that_mock_can_be_awaited():
mock = MagicMock(return_value=Future())
mock.return_value.set_result(123)
result = await mock()
assert result == 123
Run Code Online (Sandbox Code Playgroud)
在您的情况下,由于您正在修补Service(作为 传入mock),因此mock.return_value = Future()应该可以解决问题。
我最终遇到了这种骇客。
# monkey patch MagicMock
async def async_magic():
pass
MagicMock.__await__ = lambda x: async_magic().__await__()
Run Code Online (Sandbox Code Playgroud)
它仅适用于MagicMock,不适用于其他预定义的return_value
在python 3.8+中,您可以使用 AsyncMock
async def test_that_mock_can_be_awaited():
mock = AsyncMock()
mock.x.return_value = 123
result = await mock.x()
assert result == 123
Run Code Online (Sandbox Code Playgroud)
类AsyncMock对象的行为使对象被识别为异步函数,并且调用的结果是可等待的。
>>> mock = AsyncMock()
>>> asyncio.iscoroutinefunction(mock)
True
>>> inspect.isawaitable(mock())
True
Run Code Online (Sandbox Code Playgroud)
当尝试使用Python < 3.8 中的模拟对象时,我发现此注释非常有用。await您只需创建一个子类AsyncMock,该子类继承MagicMock并覆盖一个__call__方法即可成为协程:
class AsyncMock(MagicMock):
async def __call__(self, *args, **kwargs):
return super(AsyncMock, self).__call__(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
然后,在您的测试中执行以下操作:
@pytest.mark.asyncio
async def test_my_method():
# Test "my_method" coroutine by injecting an async mock
my_mock = AsyncMock()
assert await my_method(my_mock)
Run Code Online (Sandbox Code Playgroud)
你可能还想安装pytest-asyncio
| 归档时间: |
|
| 查看次数: |
3831 次 |
| 最近记录: |