Dans le guide sur les tests en python (que je dois toujours terminer, je sais…), je vous parle des objets mocks.
Si vous avez eu le plaisir de jouer avec asyncio
, vous avez du noter que unittest.mock
n’a aucun outil pour gérer gérer les coroutines.
En attendant que ce soit intégré à la stdlib, voici une petite recette :
import asyncio from unittest.mock import Mock # on utilise toute la machinerie du Mock original class AMock(Mock): def __call__(self, *args, **kwargs): # la référence du parent doit se récupérer hors # hors de la closure parent = super(AMock, self) # sauf qu'à l'appel on créé une fonction coroutine @asyncio.coroutine def coro(): # Qui fait le vrai Mock.__call__ (et donc popule l'historique # des appels), mais seulement après l'évent loop l'ait éxécuté return parent.__call__(*args, **kwargs) # On appelle la fonction coroutine pour générer une coroutine # (les coroutines marchent comme les générateurs) return coro() |
Je propose qu’en l’honneur de ce bidouillage, on l’appelle… mockoroutine !
Ca va s’utiliser comme ça:
mockorourine = AMock() yield from mockorourine() |
Après le yield from
, mockorourine.call_count == 1
, et mockorourine.assert_called_once_with()
passe.
Si vous êtes en 3.5+, on peut même faire:
class AMock(Mock): def __call__(self, *args, **kwargs): parent = super(AMock, self) async def coro(): return parent.__call__(*args, **kwargs) return coro() def __await__(self): # on delegue le await à la couroutine créée par __call__ return self().__await__() |
Puis:
await AMock() |
J’écris une bibliothèque qui s’appelle asynctest (aussi sur github et Pypi).
Elle surcharge le paquet standard unittest pour ajouter des fonctionnalités permettant de tester du code asyncio. Elle inclue des outils pour facilement faire des mocks de coroutines (y compris avec de l’auto-mocking ou patch()). Elle permet aussi d’utiliser directement des coroutines dans les fonctions de setup, teardown, test ou cleanup (ce qui fait économiser pas mal de boilerplate).
Hi. It’s cool but I don’t get how it helps me:
If I can’t use it anywhere I would use a regular coroutine, what’s the point of mocking it ?
Did I use it wrong ?
i understand nothing.
“pour gérer gérer les coroutines” : bègue ? :P
Arrête de te mocker !
C’est quoi un mock ?