2011-02-07 32 views
15

Prima la domanda, poi una spiegazione se sei interessato.generando py.test test in python

Nel contesto di py.test, come faccio a generare un ampio set di funzioni di test da un piccolo set di modelli di test-function?

Qualcosa di simile:

models = [model1,model2,model3] 
data_sets = [data1,data2,data3] 

def generate_test_learn_parameter_function(model,data): 
    def this_test(model,data): 
     param = model.learn_parameters(data) 
     assert((param - model.param) < 0.1) 
    return this_test 

for model,data in zip(models,data_sets): 
    # how can py.test can see the results of this function? 
    generate_test_learn_parameter_function(model,data) 

Spiegazione:

sto cercando difficile entrare in unit testing. Codice per "scienza", nel senso che sto scrivendo un codice che ritengo sia complicato matematicamente ma non così male da un punto di vista della programmazione, cioè ho forse cinque funzioni da testare. Che io vengo da "scienza" significa che sono abbastanza nuovo per i test unitari, ma sono stato convinto i miei amici CS che è The Thing To Do.

Il codice che sto scrivendo prende una struttura del modello, alcuni dati e apprende i parametri del modello. Quindi il mio test unitario consiste in una serie di strutture di modelli e set di dati pre-generati, e quindi una serie di circa 5 compiti di apprendimento automatico da completare su ogni struttura + dati.

Quindi, se fornisco questo codice, ho bisogno di un test per modello per attività. Ogni volta che mi viene in mente un nuovo modello, devo quindi copiare e incollare le 5 attività, cambiando la struttura pickled + i dati a cui sto puntando. Mi sembra una cattiva pratica. Idealmente, quello che mi piacerebbe sono 5 funzioni template che definiscono ciascuna delle mie 5 attività e quindi sputare solo le funzioni di test per un elenco di strutture che specifichi.

Googling su mi porta a a) fabbriche o b) chiusure, entrambe le quali aggiungono il mio cervello e mi suggeriscono che ci deve essere un modo più semplice, poiché questo problema deve essere affrontato regolarmente dai programmatori appropriati. Quindi c'è?


MODIFICA: ecco come risolvere questo problema!

def pytest_generate_tests(metafunc): 
    if "model" in metafunc.funcargnames: 
     models = [model1,model2,model3] 
     for model in models: 
      metafunc.addcall(funcargs=dict(model=model)) 

def test_awesome(model): 
    assert model == "awesome" 

Questo applicherà il test test_awesome a ciascun modello nella mia lista di modelli! Grazie @dfichter!

(NOTA: che affermano passa sempre, btw)

+0

In generale si tratta di una cattiva idea per generare il codice di prova in modo dinamico come quello. Perché allora devi scrivere test per il codice di test, ecc. 'Copia e incolla le 5 attività' Penso che questo mostri che invece di generare nuovo codice o copia-incolla, puoi trovare elementi comuni che le tue funzioni possono testare senza sapere esattamente cosa stai testando. – Falmarri

+2

Al momento sto scrivendo test che assomigliano a def test_learn: per il modello nei modelli: assert (errore

+1

@Falmarri: http://en.wikipedia.org/wiki/Copy_and_paste_programming Si prega di evitarlo a quasi tutti i costi. – lpapp

risposta

15

buon istinto. py.test supporta esattamente ciò di cui stai parlando con il suo gancio pytest_generate_tests(). Lo spiegano here.

+0

Questo è fantastico. Modificherò la mia domanda per aggiungere ciò che ho fatto alla fine, nel caso qualcuno venga qui in cerca di cose simili .. –

+0

dfichter, potresti anche dare un esempio in linea all'OP? – lpapp

+0

Questo è ora un link interrotto –

4

È inoltre possibile farlo utilizzando parametrized fixtures. Mentre ganci, è un'API per compilare plugin per Py.test, i dispositivi parametrizzati sono un modo generalizzato per realizzare dispositivi che generano più valori e genera per loro dei casi di test aggiuntivi.

I plug-in sono pensati per alcune funzionalità a livello di progetto (o di pacchetto), non sono specifiche per il caso di test e le attrezzature parametrizzate sono esattamente ciò che è necessario per parametrizzare alcune risorse per i casi di test.

Così la soluzione potrebbe essere riscritto come quella:

@pytest.fixture(params=[model1, model2, model3]) 
def model(request): 
    return request.param 

def test_awesome(model): 
    assert model == "awesome" 
Problemi correlati