在python 3.5中模拟异步调用
作者:互联网
如何使用unittest.mock.patch模拟从一个本地协程到另一个的异步调用?
我目前有一个很尴尬的解决方案:
class CoroutineMock(MagicMock):
def __await__(self, *args, **kwargs):
future = Future()
future.set_result(self)
result = yield from future
return result
然后
class TestCoroutines(TestCase):
@patch('some.path', new_callable=CoroutineMock)
def test(self, mock):
some_action()
mock.assert_called_with(1,2,3)
这有效,但看起来很难看.是否有更多的pythonic方式来做到这一点?
解决方法:
Subclassing MagicMock将为你的协同模拟生成的所有模拟传播你的自定义类.例如,AsyncMock().__ str__也将成为AsyncMock,这可能不是你想要的.
相反,您可能希望定义一个使用自定义参数创建Mock(或MagicMock)的工厂,例如side_effect = coroutine(coro).此外,将协程函数与协同程序分开可能是个好主意(如documentation中所述).
这是我想出的:
from asyncio import coroutine
def CoroMock():
coro = Mock(name="CoroutineResult")
corofunc = Mock(name="CoroutineFunction", side_effect=coroutine(coro))
corofunc.coro = coro
return corofunc
对不同对象的解释:
> corofunc:coroutine函数mock
> corofunc.side_effect():为每个调用生成的协同程序
> corofunc.coro:协程用来获得结果的模拟
> corofunc.coro.return_value:协同程序返回的值
> corofunc.coro.side_effect:可能用于引发异常
例:
async def coro(a, b):
return await sleep(1, result=a+b)
def some_action(a, b):
return get_event_loop().run_until_complete(coro(a, b))
@patch('__main__.coro', new_callable=CoroMock)
def test(corofunc):
a, b, c = 1, 2, 3
corofunc.coro.return_value = c
result = some_action(a, b)
corofunc.assert_called_with(a, b)
assert result == c
标签:python-mock,python,python-asyncio 来源: https://codeday.me/bug/20190930/1835735.html