2009-06-22 1 views
37

Ich habe ein Modul, das Unittest importiert und einige Testfälle hat. Ich möchte akzeptieren einige Befehlszeilenoptionen (zum Beispiel unten, der Name einer Datendatei), aber wenn ich versuche, die Option zu übergeben, bekomme ich die Nachricht "Option -i nicht erkannt". Ist es möglich, unit test + Optionen für die App zur Verfügung zu stellen (Hinweis: Ich verwende OptParse, um die Optionen zu behandeln)? Vielen Dank.Python, unittest: Gibt es eine Möglichkeit, Befehlszeilenoptionen an die App zu übergeben

$ python test_app_data.py -i data_1.txt 

option -i not recognized 

=====================

Follow-up: Das ist eine Implementierung der vorgeschlagenen Lösung:

import cfg_master #has the optparse option-handling code 

... 

if __name__ == '__main__':  
    #add you app's options here... 
    options_tpl = ('-i', '--in_dir', '-o', '--out_dir') 
    del_lst = [] 
    for i,option in enumerate(sys.argv): 
     if option in options_tpl: 
      del_lst.append(i) 
      del_lst.append(i+1) 

    del_lst.reverse() 
    for i in del_lst: 
     del sys.argv[i] 

    unittest.main() 
+0

Im Allgemeinen ja. In diesem Fall scheint die Antwort sehr von Details zu abhängen, die Sie nicht gegeben haben. –

+0

@jd. Ihr "Follow-up" sollte als Antwort gepostet werden - Ihre Frage sollte nur die ... na ja ... Frage enthalten. – user1251007

Antwort

45

Aufbauend auf Alex 'Antwort, es ist eigentlich ziemlich einfach argparse zu tun mit:

if __name__ == '__main__': 
    parser = argparse.ArgumentParser() 
    parser.add_argument('--input', default='My Input') 
    parser.add_argument('filename', default='some_file.txt') 
    parser.add_argument('unittest_args', nargs='*') 

    args = parser.parse_args() 
    # TODO: Go do something with args.input and args.filename 

    # Now set the sys.argv to the unittest_args (leaving sys.argv[0] alone) 
    sys.argv[1:] = args.unittest_args 
    unittest.main() 

Ich habe nicht alle Flags getestet, in Unittest passieren können, um zu sehen, ob sie funktionieren oder nicht, aber Test bestanden Namen funktioniert, zB:

python test.py --input=foo data.txt MyTest 

Läuft MyTest mit foo und data.txt.

+3

Schön! Noch besser, "unittest.main()" akzeptiert einen Parameter argv, so dass Sie sich nicht mit der globalen sys.argv, z. wie folgt: 'unit_argv = [sys.argv [0]] + args.unittest_args; unittest.main (argv = unit_argv) ' – wutz

+3

Sie können stattdessen' .parse_known_args() 'verwenden und brauchen nicht die Option' nargs = '*'; siehe [Python: führe einen unittest.TestCase ohne unittest.main()?] (http://stackoverflow.com/a/17259773) für meine Version aus. –

+0

Ich verknüpfte diese Antwort aus der von @MartijnPieters referenzierten Frage, weil der Ansatz mich ansprach. Als ich diese Antwort jedoch ausführte, funktionierte das für mich nicht, als ich die Flaggen passierte (--failfast und --catch), also kehrte ich zu Martijns Antwort zurück. –

31

In Ihrem if __name__ == '__main__': Sektion, die Sie uns nicht zeigen, werden Sie zu optparse brauchen, und dann del sys.argv[1:], bevor Sie die Kontrolle unittest Code übergeben, so dass dieser Code nicht versuchen, Ihre Befehlszeilenoptionen wieder zu interpretieren wenn yo Du hast sie schon erledigt. (Es ist ein bisschen schwieriger, einige eigene Optionen zu haben und übergeben auch einige bis unittest, obwohl es getan werden kann, wenn Sie solche komplexen Bedürfnisse haben).

+0

toll, danke; nur um zu bestätigen: zuerst erlauben opparse, die (möglicherweise multiple und variable) app-optionen zu behandeln, löschen sie dann von sys.argv, und erlauben schließlich unittest zu übernehmen? –

+0

@jd yep, das ist das Wesentliche davon! –

+0

Brilliant, danke Alex! Ich konnte das überhaupt nicht durcharbeiten: P – Skilldrick

-7

Sie sollten keine Argumente und Optionen zum Ausführen von Unittests verwenden, da Sie sie so unter anderen, weniger vorhersehbaren Bedingungen ausführen lassen. Sie sollten herausfinden, warum Sie Tests mit unterschiedlichen Daten durchführen müssen, und Ihre Testsuite so vollständig machen, dass sie den Grund aller Datensätze abdeckt, ohne jedes Mal anders ausgeführt zu werden.

+0

Ich erhalte wöchentliche Datenberichte (Dateien); Ich möchte diese neuen Berichte den Unittests zuführen, bevor ich öffentliche Berichte erstelle. Wenn sich aus irgendeinem Grund die Struktur oder der Typ der Daten geändert hat (z. B. wurde ein neues Spaltenfeld hinzugefügt, ein Datenbereich geändert und ein Fehler wird angezeigt), möchte ich sie mit den Tests abfangen. Hoffe, das macht Sinn. –

+2

sicher, aber das ist Datenvalidierung, nicht Unittesting. – ironfroggy

+2

Wie wäre es mit bedingten Test-Skipping?Ich führe alle meine Testfälle durch, indem ich die Testentdeckung von unittest mache, aber es wäre schön, Anmerkungen zu bestimmten Tests wie @skipUnless ('- full' in sys.argv) zu haben, so dass ich eine einfache Befehlszeile haben kann alle Tests laufen lassen, oder nur einige. –

1

Für kleine Standalone-Anwendungen, verwende ich eine anfängliche Sentinel-Option (-t) und rufe unittest.main() vor argparse.ArgumentParser Aufruf()

if __name__ == "__main__": 
    if len(sys.argv) > 1 and sys.argv[1] in ["-t", "--test"]: 
     del(sys.argv[1]) 
     sys.exit(unittest.main()) # pass sys.argv[ 

    p = argparse.ArgumentParser() 
    . . . 
Verwandte Themen