J'ai un module Python qui utilise la bibliothèque argparse. Comment écrire des tests pour cette section de la base de code?
python
unit-testing
argparse
pydanny
la source
la source
foo()
est appelée". Se moquer desys.argv
est la réponse si c'est le cas. Jetez un œil au package Python cli-test-helpers . Voir aussi stackoverflow.com/a/58594599/202834Réponses:
Vous devez refactoriser votre code et déplacer l'analyse vers une fonction:
Ensuite, dans votre
main
fonction, vous devez simplement l'appeler avec:(où le premier élément de
sys.argv
qui représente le nom du script est supprimé pour ne pas l'envoyer en tant que commutateur supplémentaire pendant l'opération CLI.)Dans vos tests, vous pouvez ensuite appeler la fonction parser avec la liste d'arguments avec laquelle vous voulez la tester:
De cette façon, vous n'aurez jamais à exécuter le code de votre application juste pour tester l'analyseur.
Si vous devez modifier et / ou ajouter des options à votre analyseur ultérieurement dans votre application, créez une méthode d'usine:
Vous pouvez le manipuler ultérieurement si vous le souhaitez, et un test pourrait ressembler à ceci:
la source
2
...argparse
n'est pas très convivial pour les tests car il imprime directement sursys.stderr
..."argparse portion" est un peu vague, donc cette réponse se concentre sur une partie: la
parse_args
méthode. C'est la méthode qui interagit avec votre ligne de commande et obtient toutes les valeurs passées. Fondamentalement, vous pouvez vous moquer de ce quiparse_args
revient afin qu'il n'ait pas besoin d'obtenir des valeurs à partir de la ligne de commande. Lemock
package peut être installé via pip pour les versions 2.6-3.2 de python. Il fait partie de la bibliothèque standard àunittest.mock
partir de la version 3.3.Vous devez inclure tous les arguments de votre méthode de commande
Namespace
même s'ils ne sont pas passés. Donnez à ces arguments une valeur deNone
. (voir la documentation ) Ce style est utile pour tester rapidement les cas où différentes valeurs sont passées pour chaque argument de méthode. Si vous choisissez de vous moquerNamespace
de la non-dépendance totale de l'argparse dans vos tests, assurez-vous qu'il se comporte de la même manière que laNamespace
classe réelle .Vous trouverez ci-dessous un exemple utilisant le premier extrait de code de la bibliothèque argparse.
la source
argparse
saNamespace
classe. Vous devriez vous moquerNamespace
.from unittest import mock
est maintenant la bonne méthode d'importation - enfin au moins pour python3Namespace
classe ici est exactement ce que je recherchais. Bien que le test repose toujours surargparse
, il ne repose pas sur l'implémentation particulièreargparse
du code en cours de test, ce qui est important pour mes tests unitaires. De plus, il est facile d'utiliserpytest
laparametrize()
méthode de tester rapidement diverses combinaisons d'arguments avec une maquette basée sur un modèle qui inclutreturn_value=argparse.Namespace(accumulate=accumulate, integers=integers)
.Faites en
main()
sorteargv
que votre fonction prenne comme argument plutôt que de la laisser liresys.argv
comme elle le fera par défaut :Ensuite, vous pouvez tester normalement.
la source
sys.argv.append()
, puis appelezparse()
, vérifiez les résultats et répétez.if __name__ == "__main__":
analyse des appels et vidage / évaluation des résultats, puis testez-le à partir d'un fichier batch / bash.la source
Je ne voulais pas modifier le script
sys.argv
de diffusion d' origine, donc je me suis simplement moqué de la partie dans argparse.Cela s'arrête si l'implémentation d'argparse change mais suffit pour un script de test rapide. La sensibilité est de toute façon beaucoup plus importante que la spécificité dans les scripts de test.
la source
Une façon simple de tester un analyseur est:
Une autre façon est de modifier
sys.argv
et d'appelerargs = parser.parse_args()
Il existe de nombreux exemples de tests
argparse
danslib/test/test_argparse.py
la source
parse_args
jette unSystemExit
et imprime sur stderr, vous pouvez attraper les deux:Vous inspectez stderr (en utilisant
err.seek(0); err.read()
mais généralement cette granularité n'est pas requise.Vous pouvez maintenant utiliser
assertTrue
ou tout autre test que vous aimez:Sinon, vous aimeriez peut-être attraper et renvoyer une erreur différente (au lieu de
SystemExit
):la source
Lorsque
argparse.ArgumentParser.parse_args
je passe des résultats à une fonction, j'utilise parfois unnamedtuple
pour simuler des arguments pour les tests.la source
Pour tester la CLI (interface de ligne de commande), et non la sortie de commande, j'ai fait quelque chose comme ça
la source