编程语言
首页 > 编程语言> > 在python 3.5中模拟异步调用

在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