J'ai écrit un simple client HTTP en utilisant aiohttp et j'essaie de le tester en corrigeant aiohttp.ClientSession
et aiohttp.ClientResponse
. Cependant, il semble que le décorateur unittest.mock.patch
ne respecte pas mon code asynchrone. En un clin d'œil, je dirais que c'est une sorte de disparité des espaces de noms.Test du client aiohttp avec unittest.mock.patch
Voici un exemple minimal:
from aiohttp import ClientSession
async def is_ok(url:str) -> bool:
async with ClientSession() as session:
async with session.request("GET", url) as response:
return (response.status == 200)
J'utilise un décorateur asynchrone pour le test, comme décrit dans this answer. Alors, voici ma tentative de test:
import unittest
from unittest.mock import MagicMock, patch
from aiohttp import ClientResponse
from my.original.module import is_ok
class TestClient(unittest.TestCase):
@async_test
@patch("my.original.module.ClientSession", spec=True)
async def test_client(self, mock_client):
mock_response = MagicMock(spec=ClientResponse)
mock_response.status = 200
async def _mock_request(*args, **kwargs):
return mock_response
mock_client.request = mock_response
status = await is_ok("foo")
self.assertTrue(status)
Mon is_ok
coroutine fonctionne très bien quand il est utilisé dans, disons, __main__
, mais quand je lance le test, il me donne une erreur qui indique que la fonction session.request
n'a pas été moqué par mon appel patch
. (Plus précisément, il est dit "Impossible d'analyser le nom d'hôte de l'URL 'foo'", ce qu'il devrait si n'étaient pas mocked.)
Je suis incapable d'échapper à ce comportement. J'ai essayé:
- Importation
is_ok
après la moquerie est fait. - Diverses combinaisons d'attribution se moque de
mock_client
etmock_client.__aenter__
, la mise enmock_client.request
-MagicMock(return_value=mock_response)
ou en utilisantmock_client().request
, etc. - Rédaction d'une
ClientSession
simulée avec des méthodes spécifiques__aenter__
et__aexit__
et l'utiliser dans l'argumentnew
-patch
.
Aucun de ces éléments ne semble faire la différence. Si je mets des assertions dans is_ok
pour tester que ClientSession
est une instance de MagicMock
, alors ces assertions échouent quand j'exécute le test (comme, encore une fois, ils le feraient quand le code n'est pas patché). Cela m'amène à ma théorie de la discordance des espaces de noms: la boucle d'événements s'exécute dans un espace de noms différent ciblé par patch
.
Soit ça, ou je fais quelque chose de stupide!
C'est un peu horrible, mais OK ... – Xophmeister
C'est comme une utilisation de base de données de test au lieu de se moquer de toutes les exécutions SQL. –
Oui, un test d'intégration. Compréhensible et nécessaire, mais sans doute exagéré si vous voulez juste tester le flux de contrôle. – Xophmeister