2012-11-21 11 views
10

Sto lavorando su un programma a riga di comando-Interface pitone, e lo trovo noioso quando si fa collaudi, per esempio, qui sono le informazioni aiuto del programma:Python CLI unità programma di test

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 

Quando Ho apportato delle modifiche al programma e voglio testare qualcosa, devo aprire un terminale, digitare il comando (con opzioni e argomenti), digitare enter, e vedere se si verifica un errore durante l'esecuzione. Se l'errore si verifica davvero, devo tornare all'editor e controllare il codice da cima a fondo, indovinare dove posizioni bug, apportare piccole modifiche, scrivere print linee, tornare al terminale, eseguire nuovamente il comando ...

In modo ricorsivo.

Quindi la mia domanda è: qual è il modo migliore per eseguire test con il programma CLI, può essere altrettanto semplice come come test di unità con normali script Python?

risposta

3

La risposta è sì, può usare le unit test e dovrebbe. Se il tuo codice è ben strutturato, dovrebbe essere abbastanza facile testare ciascun componente separatamente, e se è necessario puoi sempre prendere in giro sys.argv per simularlo eseguendolo con argomenti diversi.

0

Questo non è specificamente per Python, ma quello che faccio per testare gli script della riga di comando è di eseguirli con vari ingressi e opzioni predeterminati e memorizzare l'output corretto in un file. Quindi, per testarli quando apporto le modifiche, eseguo semplicemente il nuovo script e convogliamo l'output in diff correct_output -. Se i file sono uguali, non emette nulla. Se sono diversi, ti mostra dove. Questo funzionerà solo se sei su Linux o OS X; su Windows, dovrai ottenere MSYS.

Esempio:

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

Per rendere ancora più facile, è possibile aggiungere tutti questi test viene eseguito al 'make test' obiettivo Makefile, che suppongo già. ;)

se si esegue molti di questi in una sola volta, si potrebbe rendere un po 'più evidente in cui ognuno si conclude con l'aggiunta di un tag fallire:

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

1

Quindi la mia domanda è, qual è il modo migliore per eseguire test con il programma CLI, può essere semplice come test dell'unità con normali script Python?

L'unica differenza è che quando si esegue modulo Python come uno script, il suo attributo __name__ è impostato su '__main__'. Quindi in generale, se si intende eseguire lo script da linea di comando dovrebbe avere forma seguente:

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() 

Ora non v'è alcuna differenza, come si usa: come uno script o come modulo. Quindi, all'interno del tuo codice di test dell'unità, puoi semplicemente importare la funzione foo, chiamarla e fare tutte le asserzioni che vuoi.

-1

È possibile utilizzare il modulo unittest di serie:

# python -m unittest <test module> 

o utilizzare nose come un framework di test.Basta scrivere i classici file unittest in una directory separata ed eseguire:

# nosetests <test modules directory> 

Scrivere unittests è facile. Basta seguire online manual for unittesting

1

Non testerei il programma nel suo complesso questa non è una buona strategia di test e potrebbe non rilevare il vero punto dell'errore. L'interfaccia CLI è solo front-end di un'API. Testate l'API tramite i vostri test unitari e quindi quando apportate una modifica a una parte specifica, avete un caso di test per esercitare tale cambiamento.

Quindi, ristrutturare l'applicazione in modo da testare l'API e non l'applicazione stessa. Ma puoi avere un test funzionale che esegue effettivamente l'applicazione completa e verifica che l'output sia corretto.

In breve, sì, testare il codice equivale a testare qualsiasi altro codice, ma è necessario testare le singole parti piuttosto che la loro combinazione nel suo complesso per garantire che le proprie modifiche non interrompano tutto.

6

Penso che sia perfettamente funzionante testare a livello di un programma intero. È ancora possibile testare un aspetto/opzione per test. In questo modo puoi essere sicuro che il programma funziona davvero nel suo complesso. Scrivere test unitari di solito significa che è possibile eseguire i test più rapidamente e che i problemi di solito sono più facili da interpretare/comprendere. Ma i test unitari sono in genere più legati alla struttura del programma, che richiede un maggiore sforzo di refactoring quando si cambiano le cose internamente.

In ogni caso, utilizzando py.test, ecco un piccolo esempio per testare un latin1 alla conversione utf8 per pyconv ::

# 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 

Dopo aver installato pytest ("PIP installare pytest") è possibile eseguire in questo modo ::

$ 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 ========================= 

L'esempio riutilizza alcuni meccanismi interni di test effettuati da pytest sfruttando meccanismo di fissaggio pytest, vedi http://pytest.org/latest/fixture.html. Se ti dimentichi dei dettagli per un momento, puoi semplicemente lavorare dal fatto che "run" e "tmpdir" sono forniti per aiutarti a preparare ed eseguire i test. Se vuoi giocare, puoi provare ad inserire una dichiarazione di asserzione fallita o semplicemente "asserire 0" e poi guardare al traceback o pubblicare "py.test --pdb" per inserire un prompt di python.

+0

È possibile utilizzare stdin e stdin con l'apparecchio 'run'? –