2012-11-21 5 views
10

ich auf einem Python-Kommandozeilen-Interface-Programm arbeite, und ich finde es langweilig, wenn testings tun, zum Beispiel, hier ist die Hilfe-Informationen des Programms:Python CLI Programm Unit-Tests

usage: pyconv [-h] [-f ENCODING] [-t ENCODING] [-o file_path] file_path 

Convert text file from one encoding to another. 

positional arguments: 
    file_path 

optional arguments: 
    -h, --help   show this help message and exit 
    -f ENCODING, --from ENCODING 
         Encoding of source file 
    -t ENCODING, --to ENCODING 
         Encoding you want 
    -o file_path, --output file_path 
         Output file path 

Wenn Ich habe Änderungen am Programm vorgenommen und möchte etwas testen, ich muss ein Terminal öffnen, den Befehl eingeben (mit Optionen und Argumenten), geben Sie eingeben, und sehen, ob ein Fehler beim Ausführen auftritt. Wenn ein Fehler wirklich auftritt, muss ich zurück zum Editor gehen und den Code von Anfang bis Ende prüfen, wo die Bug-Positionen, kleine Änderungen, schreiben print Zeilen, Rückkehr zum Terminal, Befehl erneut ausführen ...

Rekursiv.

Also meine Frage ist, was ist der beste Weg, um Tests mit CLI-Programm zu tun, kann es so einfach sein als Unit-Test mit normalen Python-Skripten?

Antwort

3

Die kurze Antwort ist ja, Sie kann Komponententests verwenden und sollte. Wenn Ihr Code gut strukturiert ist, sollte es ziemlich einfach sein, jede Komponente einzeln zu testen, und wenn Sie müssen, können Sie immer simulieren, sys.argv zu simulieren, es mit verschiedenen Argumenten auszuführen.

0

Dies ist nicht speziell für Python, aber was ich tue, um Befehlszeilenskripte zu testen, ist, sie mit verschiedenen vorgegebenen Eingaben und Optionen auszuführen und die korrekte Ausgabe in einer Datei zu speichern. Um sie dann zu testen, wenn ich Änderungen vornahm, führte ich einfach das neue Skript aus und leitete die Ausgabe in diff correct_output -. Wenn die Dateien identisch sind, wird nichts ausgegeben. Wenn sie anders sind, zeigt es Ihnen, wo. Dies funktioniert nur, wenn Sie Linux oder OS X verwenden. Unter Windows müssen Sie MSYS erhalten.

Beispiel:

python mycliprogram --someoption "some input" | diff correct_output -

Um es noch einfacher zu machen, können Sie all diesen Test hinzufügen läuft zu Ihrer 'make test' Makefile-Target, das ich euch schon übernehmen habe. ;)

Wenn Sie auf einmal viele von ihnen laufen, könnte man es ein wenig deutlicher machen, wo jeder durch Zugabe eines nicht-Tag endet:

python mycliprogram --someoption "some input" | diff correct_output - || tput setaf 1 && echo "FAILED"

1

Also meine Frage ist, was ist der beste Weg, um Tests mit CLI-Programm zu tun, kann es so einfach sein wie Unit-Tests mit normalen Python-Skripten?

Der einzige Unterschied besteht darin, dass, wenn Sie Python-Modul als Skript ausführen, sein __name__ Attribut '__main__' gesetzt. So im Allgemeinen, wenn Sie Ihren Skript von der Kommandozeile ausgeführt werden sollte folgende Form hat:

import sys 

# function and class definitions, etc. 
# ... 
def foo(arg): 
    pass 

def main(): 
    """Entry point to the script""" 

    # Do parsing of command line arguments and other stuff here. And then 
    # make calls to whatever functions and classes that are defined in your 
    # module. For example: 
    foo(sys.argv[1]) 


if __name__ == '__main__': 
    main() 

Jetzt gibt es keinen Unterschied, wie Sie es verwenden würden: als Skript oder als Modul. In Ihrem Unit-Test-Code können Sie einfach die foo-Funktion importieren, aufrufen und beliebige Behauptungen eingeben.

-1

können Sie Standard-Unittest-Modul verwenden:

# python -m unittest <test module> 

oder nose als Test-Framework verwenden.Schreiben Sie einfach klassische Unittest-Dateien in ein separates Verzeichnis und führen Sie folgende Schritte aus:

# nosetests <test modules directory> 

Schreiben von Komponententests ist einfach. Folgen Sie einfach

1

Ich würde das Programm als Ganzes nicht testen, das ist keine gute Teststrategie und möglicherweise nicht den tatsächlichen Ort des Fehlers zu fangen. Die CLI-Schnittstelle ist nur das Frontend einer API. Sie testen die API über Ihre Komponententests und wenn Sie dann eine Änderung an einem bestimmten Teil vornehmen, haben Sie einen Testfall, um diese Änderung auszuführen.

Also, restrukturieren Sie Ihre Anwendung, so dass Sie die API und nicht die Anwendung selbst testen. Sie können jedoch einen Funktionstest durchführen, der tatsächlich die vollständige Anwendung ausführt und überprüft, ob die Ausgabe korrekt ist.

Kurz gesagt, ist das Testen des Codes identisch mit dem Testen von anderem Code, aber Sie müssen die einzelnen Teile und nicht ihre Kombination als Ganzes testen, um sicherzustellen, dass Ihre Änderungen nicht alles kaputt machen.

6

Ich denke, es ist völlig in Ordnung, funktional auf einer ganzen Programm-Ebene zu testen. Es ist immer noch möglich, einen Aspekt/eine Option pro Test zu testen. So können Sie sicher sein, dass das Programm wirklich als Ganzes funktioniert. Das Schreiben von Komponententests bedeutet normalerweise, dass Sie Ihre Tests schneller ausführen können und dass Fehler in der Regel einfacher zu interpretieren sind. Unit-Tests sind jedoch in der Regel stärker an die Programmstruktur gebunden, so dass bei internen Änderungen mehr Refaktorierungsaufwand erforderlich ist.

Wie auch immer, mit py.test, hier ist ein kleines Beispiel für eine latin1 auf utf8 Konvertierung für pyconv Testen ::

# content of test_pyconv.py 

import pytest 

# we reuse a bit of pytest's own testing machinery, this should eventually come 
# from a separatedly installable pytest-cli plugin. 
pytest_plugins = ["pytester"] 

@pytest.fixture 
def run(testdir): 
    def do_run(*args): 
     args = ["pyconv"] + list(args) 
     return testdir._run(*args) 
    return do_run 

def test_pyconv_latin1_to_utf8(tmpdir, run): 
    input = tmpdir.join("example.txt") 
    content = unicode("\xc3\xa4\xc3\xb6", "latin1") 
    with input.open("wb") as f: 
     f.write(content.encode("latin1")) 
    output = tmpdir.join("example.txt.utf8") 
    result = run("-flatin1", "-tutf8", input, "-o", output) 
    assert result.ret == 0 
    with output.open("rb") as f: 
     newcontent = f.read() 
    assert content.encode("utf8") == newcontent 

Nach pytest Installation („BIB pytest installieren“) können Sie es wie folgt ausführen ::

$ py.test test_pyconv.py 
=========================== test session starts ============================ 
platform linux2 -- Python 2.7.3 -- pytest-2.4.5dev1 
collected 1 items 

test_pyconv.py . 

========================= 1 passed in 0.40 seconds ========================= 

Das Beispiel wieder verwendet einige interne Maschinerie der eigenen Prüfung pytest durch pytest des Befestigungsmechanismus nutzt, siehe http://pytest.org/latest/fixture.html. Wenn Sie die Details für einen Moment vergessen, können Sie nur daran arbeiten, dass "run" und "tmpdir" Ihnen helfen, Tests vorzubereiten und durchzuführen. Wenn Sie spielen möchten, können Sie versuchen, eine fehlgeschlagene assert-Anweisung einzufügen oder einfach "assert 0" zu setzen und dann das Trace-Back oder das Problem "py.test --pdb" zu betrachten, um eine Python-Eingabeaufforderung einzugeben.

+0

Ist es möglich, stdin und stdin mit dem 'run' Fixture zu verwenden? –