Selezione dei casi di test da eseguire controllando cosa è cambiato

1

Problema:

Se l'esecuzione di tutti i test case richiede troppo tempo, specifica manualmente un sottoinsieme di test da eseguire durante lo sviluppo. Ma quando finalmente spingo a CI, può succedere che abbia rotto qualche altro test o una funzionalità che viene controllata da loro. Quindi ho eseguito l'underselected test. Allo stesso modo, a volte dopo aver apportato delle modifiche non so quali test particolari dovrei eseguire, quindi eseguo una selezione troppo ampia (o ottimisticamente la lascia in CI :)).

Soluzione proposta:

Un flag in un test runner (ad esempio pytest ) che include in un test eseguito qualsiasi caso di test che può essere influenzato da ciò che è cambiato nel progetto. Non una soluzione a prova di proiettile, ma un'approssimazione di esso. Può ad esempio: dopo ogni prova eseguire la copertura del negozio di ogni caso di test separatamente. Quindi controlla se le linee di ogni copertura sono attualmente diverse (o c'è un nuovo test) - se è così, aggiungilo ai test da eseguire. Può anche monitorare quali file non di origine sono accessibili e gli hash di essi.

Come puoi vedere, ci sono ancora casi in cui alcuni test potrebbero interrompersi e non saranno inclusi. Ma il punto è di ridurre radicalmente la probabilità che un programmatore sottolieni i casi di test o sprechi un po 'di tempo in attesa dell'esecuzione di un test troppo ampio. Se ha funzionato in modo accettabile, per impostazione predefinita potremmo utilizzare solo questo flag e non definire l'ambito del test manualmente. Solo su CI ci sarebbe un test completo.

Domanda:

Ci sono grossi problemi che seppelliscono questa idea? So che i test dovrebbero essere rapidi e più si toccano, meno dovrebbe essere il tipo. Ma dire che non vogliamo queste cose "perché dovremmo risolvere il problema sorgente" (la durata della suite di test completa) è come dire che non abbiamo bisogno di test perché non dovremmo creare bug in primo luogo - non molto utile.

Possibilmente grandi problemi che vedo:

  1. la creazione di una copertura separata per ogni caso di test potrebbe essere un grosso sovraccarico
  2. ^ potrebbe non essere nemmeno possibile con gli strumenti correnti
  3. la somma dei costi di tempo di tali test aggiunti automaticamente può vanificare lo scopo (l'aggiunta di qualcosa a livello di modulo (in Python) può eseguire molti test)
posta Ctrl-C 11.05.2018 - 17:24
fonte

2 risposte

1

Potresti essere interessato a runner di test incrementali come pytest-incremental . pytest-incremental analizza le istruzioni di importazione nel codice e nel codice di test per ricavare un grafico di dipendenza, che utilizza per riordinare e deselezionare i test che non hanno esito negativo, date le modifiche apportate dall'ultima esecuzione di test.

Nota, non ho mai usato questo specifico plugin pytest, ma ho usato un analizzatore incrementale simile con nosetests. Nella mia esperienza, il runner di test incrementale in python generalmente funziona bene fino a quando non esegui importazioni dinamiche (cioè utilizzando import o importlib) e hai una buona igiene di test (ad esempio, mantieni i tuoi test e le loro impostazioni indipendente).

Di solito combino il runner di test incrementale con un watcher di directory, quindi i test vengono eseguiti automaticamente ogni volta che salvi il file nel mio editor di testo. Un plugin come pytest-watch potrebbe essere utile qui.

Inoltre, ti suggerisco di utilizzare segno di pita per contrassegnare i casi di test con indicatori diversi . Puoi quindi utilizzare pytest -m per selezionare diversi indicatori. Ad esempio, potresti voler contrassegnare tutti i test di slow / integration, in modo che tu possa fare pytest -m "not integration" per saltare i test di integrazione lenti.

Non consiglierei un rapporto sulla copertura da esecuzioni di test incrementali. Suggerirei di creare un hook git (o qualsiasi altra funzionalità simile nel tuo VCS) o di generare il tuo report di copertura nel tuo CI. Il reporting di copertura di solito rallenta notevolmente il test, quindi è generalmente indesiderabile attivarlo sempre durante lo sviluppo.

    
risposta data 10.06.2018 - 19:11
fonte
0

Proporrei di usare il sistema make per questo. Il test case dipende solo da quei file che sono necessari. Quindi crea un file .test_a_successful con il comando touch : touch .test_a_successful .

Quindi, essenzialmente avresti il seguente Makefile :

.test_a_successful: testa.py file1.py file2.py file3.py
        python testa.py
        touch .test_a_successful

Ogni volta che cambi file4.py , il test non verrà rieseguito inutilmente.

Lo svantaggio ovviamente è che poiché Python è un linguaggio interpretato, potresti in futuro caricare file4.py e poi dimenticare di includerlo come dipendenza in Makefile .

Se hai usato un linguaggio compilato come C, la maggior parte ha un meccanismo di autogenerazione delle dipendenze del file di intestazione in Makefile . Tuttavia, non sto proponendo di usare C al posto di Python senza conoscere tutti i dettagli del tuo progetto. Solo una cosa interessante da considerare.

    
risposta data 11.05.2018 - 17:43
fonte

Leggi altre domande sui tag