Wie schreibst du Tests für den argparse Teil eines Python-Moduls?

Ich habe ein Python-Modul, das die argparse-Bibliothek verwendet. Wie schreibe ich Tests für diesen Abschnitt der Codebasis?

  • Unit Test Suite in Python
  • Wie teste ich eine Flasche RESTful API
  • Wie kann ich alle Python-Unit-Tests in einem Verzeichnis ausführen?
  • Wie kommt es, dass es kein C # Äquivalent von Python's Doctest Feature gibt?
  • Verlangt Python die Notwendigkeit von Unit-Tests?
  • Wie kann ich testen, ob mein Code die entsprechenden argparse Ausnahmen werft?
  • Unbekannt mit Befehlszeilenargumenten
  • Django: Block Internetanschluss für Testzwecke
  • 6 Solutions collect form web for “Wie schreibst du Tests für den argparse Teil eines Python-Moduls?”

    Sie sollten Ihren Code umgestalten und das Parsing zu einer Funktion verschieben:

    def parse_args(args): parser = argparse.ArgumentParser(...) parser.add_argument... # ...Create your parser as you like... return parser.parse_args(args) 

    Dann in deiner Hauptfunktion solltest du es einfach anrufen:

     parser = parse_args(sys.argv[1:]) 

    ( sys.argv das erste Element von sys.argv , das den sys.argv repräsentiert, entfernt wird, um es nicht als zusätzlichen Schalter während des CLI-Vorgangs zu senden.)

    In deinen Tests kannst du dann die Parser-Funktion mit einer beliebigen Liste von Argumenten anrufen, die du mit testen willst:

     def test_parser(self): parser = parse_args(['-l', '-m']) self.assertTrue(parser.long) # ...and so on. 

    Auf diese Weise müssen Sie den Code Ihrer Anwendung niemals ausführen, um den Parser zu testen.

    Wenn Sie zu Ihrem Parser später in Ihrer Anwendung wechseln und / oder hinzufügen möchten, dann erstellen Sie eine Werksmethode:

     def create_parser(): parser = argparse.ArgumentParser(...) parser.add_argument... # ...Create your parser as you like... return parser 

    Sie können es später manipulieren, wenn Sie wollen, und ein Test könnte wie folgt aussehen:

     class ParserTest(unittest.TestCase): def setUp(self): self.parser = create_parser() def test_something(self): parsed = self.parser.parse_args(['--something', 'test']) self.assertEqual(parsed.something, 'test') 

    "Argparse portion" ist ein bisschen vage so diese Antwort konzentriert sich auf einen Teil: die parse_args Methode. Dies ist die Methode, die mit Ihrer Befehlszeile interagiert und alle übergebenen Werte erhält. Grundsätzlich können Sie verspotten, was parse_args zurückgibt, damit es nicht wirklich Werte aus der Kommandozeile erhält.

     import argparse import mock @mock.patch('argparse.ArgumentParser.parse_args', return_value=argparse.Namespace(kwarg1=value, kwarg2=value)) def test_command(mock_args): pass 

    Du musst alle Armbänder deiner Befehlsmethode im Namespace einschließen, auch wenn sie nicht übergeben werden. Geben Sie diesen Args einen Wert von None . (Siehe die docs ) Dieser Stil ist nützlich, um schnell Tests für Fälle zu tun, in denen für jedes Methodenargument unterschiedliche Werte übergeben werden. Wenn Sie sich entscheiden, Namespace selbst für totale Argparse nicht-Vertrauen in Ihre Tests zu verspotten, stellen Sie sicher, dass es sich ähnlich wie die tatsächliche Namespace Klasse verhält.

    1. Füllen Sie Ihre arg-Liste mit sys.argv.append() und dann parse() , überprüfen Sie die Ergebnisse und wiederholen.
    2. Rufen Sie aus einer Batch / Bash-Datei mit Ihren Flags und eine Dump Args Flagge.
    3. Setzen Sie alle Ihre Argument-Parsing in einer separaten Datei und in der if __name__ == "__main__": call if __name__ == "__main__": und Dump / Auswertung der Ergebnisse dann testen Sie dies aus einer Batch / Bash-Datei.

    Eine einfache Möglichkeit, einen Parser zu testen, ist:

     parser = ... parser.add_argument('-a',type=int) ... argv = '-a 1 foo'.split() # or ['-a','1','foo'] args = parser.parse_args(argv) assert(args.a == 1) ... 

    Eine andere Möglichkeit ist, sys.argv zu modifizieren und args = parser.parse_args()

    Es gibt viele Beispiele für das Testen von argparse in lib/test/test_argparse.py

    Machen Sie Ihre main() -Funktion nehmen argv als Argument anstatt lassen Sie es von sys.argv lesen, wie es standardmäßig ist :

     # mymodule.py import argparse import sys def main(args): parser = argparse.ArgumentParser() parser.add_argument('-a') process(**vars(parser.parse_args(args))) return 0 def process(a=None): pass if __name__ == "__main__": sys.exit(main(sys.argv[1:])) 

    Dann können Sie normal testen.

     import mock from mymodule import main @mock.patch('mymodule.process') def test_main(process): main([]) process.assert_call_once_with(a=None) @mock.patch('foo.process') def test_main_a(process): main(['-a', '1']) process.assert_call_once_with(a='1') 

    Ich fand, dass der einfachste Weg, für mich zumindest, war nur zu überprüfen, sys.argv [0] so sehen, wenn Python als python -m unittest lief python -m unittest und nicht parsen nichts, wenn das der Fall war.

     import sys import argparse parser = argparse.ArgumentParser() parser.add_argument('--outdir', help='Directory to output to', \ default='out') parser.add_argument('--file', help='Input file', \ default='section') parser.add_argument('--word', help='Word to look up') if sys.argv[0] == 'python -m unittest': args = parser.parse_args([]) else: args = parser.parse_args() 
    Python ist die beste Programmiersprache der Welt.