Ich habe ein Python-Modul, das die Argparse-Bibliothek verwendet. Wie schreibe ich Tests für diesen Abschnitt der Codebasis?
python
unit-testing
argparse
pydanny
quelle
quelle
foo()
aufgerufen". Verspottensys.argv
ist die Antwort, wenn das der Fall ist. Schauen Sie sich das Python-Paket von cli-test-helpers an. Siehe auch stackoverflow.com/a/58594599/202834Antworten:
Sie sollten Ihren Code umgestalten und die Analyse in eine Funktion verschieben:
Dann
main
sollten Sie es in Ihrer Funktion einfach aufrufen mit:(wobei das erste Element
sys.argv
, das den Skriptnamen darstellt, entfernt wird, um ihn während des CLI-Vorgangs nicht als zusätzlichen Switch zu senden.)In Ihren Tests können Sie dann die Parser-Funktion mit einer beliebigen Liste von Argumenten aufrufen, mit denen Sie sie testen möchten:
Auf diese Weise müssen Sie niemals den Code Ihrer Anwendung ausführen, nur um den Parser zu testen.
Wenn Sie später in Ihrer Anwendung Optionen ändern und / oder Optionen zu Ihrem Parser hinzufügen müssen, erstellen Sie eine Factory-Methode:
Sie können es später bearbeiten, wenn Sie möchten, und ein Test könnte folgendermaßen aussehen:
quelle
2
...argparse
ist nicht sehr testfreundlich, da es direkt ansys.stderr
..."argparse portion" ist etwas vage, daher konzentriert sich diese Antwort auf einen Teil: die
parse_args
Methode. Dies ist die Methode, die mit Ihrer Befehlszeile interagiert und alle übergebenen Werte abruft. Grundsätzlich können Sie verspotten, wasparse_args
zurückgegeben wird, damit keine Werte über die Befehlszeile abgerufen werden müssen. Dasmock
Paket kann über pip für Python-Versionen 2.6-3.2 installiert werden. Es ist Teil der Standardbibliothekunittest.mock
ab Version 3.3.Sie müssen alle Argumente Ihrer Befehlsmethode einschließen,
Namespace
auch wenn sie nicht übergeben werden. Geben Sie diesen Argumenten den Wert vonNone
. (siehe Dokumentation ) Dieser Stil ist nützlich, um schnell Tests für Fälle durchzuführen, in denen für jedes Methodenargument unterschiedliche Werte übergeben werden. Wenn Sie sichNamespace
in Ihren Tests dafür entscheiden, sich selbst zu verspotten, um sich nicht auf Vertrauen zu verlassen, stellen Sie sicher, dass es sich ähnlich wie die eigentlicheNamespace
Klasse verhält .Unten sehen Sie ein Beispiel mit dem ersten Snippet aus der Argparse-Bibliothek.
quelle
argparse
und seinerNamespace
Klasse ab. Du solltest dich lustig machenNamespace
.from unittest import mock
ist jetzt die richtige Importmethode - zumindest für Python3Namespace
Klasse hier ist genau das, wonach ich gesucht habe. Obwohl sich der Test immer noch darauf stütztargparse
, hängt er nicht von der speziellen Implementierung des zuargparse
testenden Codes ab, was für meine Komponententests wichtig ist. Darüber hinaus ist es einfach, mitpytest
derparametrize()
Methode verschiedene Argumentkombinationen schnell mit einem Vorlagen-Mock zu testen, das Folgendes enthältreturn_value=argparse.Namespace(accumulate=accumulate, integers=integers)
.Lassen Sie Ihre
main()
Funktionargv
als Argument nehmen, anstatt sie standardmäßig lesen zusys.argv
lassen :Dann können Sie normal testen.
quelle
sys.argv.append()
und rufen Sie dann aufparse()
, überprüfen Sie die Ergebnisse und wiederholen Sie den Vorgang.if __name__ == "__main__":
Aufrufanalyse ein und sichern / bewerten Sie die Ergebnisse. Testen Sie diese dann anhand einer Batch- / Bash-Datei.quelle
Ich wollte das ursprüngliche Serving-Skript nicht ändern, also habe ich den
sys.argv
Teil in Argparse nur verspottet .Dies bricht ab, wenn sich die Implementierung von argparse ändert, aber genug für ein schnelles Testskript. Sensibilität ist sowieso viel wichtiger als Spezifität in Testskripten.
quelle
Eine einfache Möglichkeit zum Testen eines Parsers ist:
Eine andere Möglichkeit besteht darin, Änderungen vorzunehmen
sys.argv
und aufzurufenargs = parser.parse_args()
Es gibt viele Beispiele für Tests
argparse
inlib/test/test_argparse.py
quelle
parse_args
wirft einSystemExit
und druckt auf stderr, Sie können beide fangen:Sie inspizieren stderr (mit,
err.seek(0); err.read()
aber im Allgemeinen ist keine Granularität erforderlich.Jetzt können Sie beliebige
assertTrue
Tests verwenden oder verwenden:Alternativ möchten Sie möglicherweise einen anderen Fehler abfangen und erneut auslösen (anstelle von
SystemExit
):quelle
Wenn
argparse.ArgumentParser.parse_args
ich Ergebnisse von an eine Funktion übergebe, verwende ich manchmal anamedtuple
, um Argumente zum Testen zu verspotten.quelle
Zum Testen der CLI (Befehlszeilenschnittstelle) und nicht der Befehlsausgabe habe ich so etwas getan
quelle