2017-09-27 6 views
0

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 et mock_client.__aenter__, la mise en mock_client.request-MagicMock(return_value=mock_response) ou en utilisant mock_client().request, etc.
  • Rédaction d'une ClientSession simulée avec des méthodes spécifiques __aenter__ et __aexit__ et l'utiliser dans l'argument new-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!

Répondre

-1

Il est déconseillé de railler ClientSession.

Recommandé est la création de faux serveur et l'envoi réels demandes à lui.

Regardez aiohttp example.

+0

C'est un peu horrible, mais OK ... – Xophmeister

+2

C'est comme une utilisation de base de données de test au lieu de se moquer de toutes les exécutions SQL. –

+0

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