Lorsque j'essayais de simuler une fonction asynchrone en unittest avec MagicMock, j'ai eu cette exception:
TypeError: l'objet MagicMock ne peut pas être utilisé dans l'expression 'wait'
Avec un exemple de code comme:
# 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()
Comment dois-je le réparer avec les bibliothèques python3 intégrées?
Je me suis retrouvé avec ce hack.
# monkey patch MagicMock
async def async_magic():
pass
MagicMock.__await__ = lambda x: async_magic().__await__()
Cela ne fonctionne que pour MagicMock, pas pour les autres valeurs de retour prédéfinies
Vous pouvez obtenir des simulations pour renvoyer des objets qui peuvent être attendus en utilisant un Future . Ce qui suit est un cas de test pytest , mais quelque chose de similaire devrait être possible avec nittest .
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
Dans votre cas, puisque vous patchez Service
(qui est passé sous la forme mock
), mock.return_value = Future()
devrait faire l'affaire.
shaun shia a fourni une très bonne solution universelle, mais j'ai trouvé ce que dans python 3.8 vous pouvez utiliser juste @patch('__main__.Service', new=AsyncMock)