Come fare in modo che un test dipenda dai risultati di un altro test?


13

Supponiamo che esista una classe di utilità che fornisce alcuni metodi statici comuni utilizzati ovunque nel codice da molte altre classi.

Come progettereste i test unitari per i consumatori dell'utilità in modo che i loro test falliscano se uno qualsiasi dei test di utilità non viene superato? Puoi farlo o devi controllarlo tu stesso se i test della classe di utilità sono tutti verdi?

Ad esempio ho un'utilità di suddivisione dei messaggi che viene utilizzata (o piuttosto il suo output) da un parser di messaggi. Mi piacerebbe essere sicuro che lo splitter di messaggi funzioni correttamente prima che venga testato il parser di messaggi.

Ho scritto dei test per entrambi ma c'è un modo per collegarli e far dipendere un test dal risultato di qualche altro test?

Non sono riuscito a trovare un tag adatto per questo, ma sto usando il motore di unit test di Visual Studio.


1
Capisco che il parser non funziona correttamente se l'utilità fallisce. Ma se esegui i test vedrai che i test di utilità falliscono. Perché vuoi che anche altri test falliscano?
Eugen Martynov,

1
Non ho mai sentito parlare di qualcuno che lo desiderasse prima. Cosa stai cercando di raggiungere?
Esben Skov Pedersen,


Uso alcune delle funzioni di utilità per preparare i dati per i test del parser, quindi vorrei essere assolutamente sicuro che l'utilità funzioni correttamente prima di provare qualcos'altro.
t3chb0t,

3
@ t3chb0t Se vuoi assicurarti che la tua utility funzioni, allora devi scrivere unit test per verificare la tua utility. I test unitari dovrebbero essere atomici. Hai sempre e solo voluto che testassero un singolo componente.
maple_shaft

Risposte:


11

Non ha senso accertarsi che ogni difetto del sistema superi esattamente un test.

Una suite di test ha un solo compito: verificare che non vi siano difetti noti. Se c'è un difetto, non importa se un test fallisce o 10. Se ti abitui al fallimento della tua suite di test, se provi a valutare quanto "cattivo" il tuo programma contando i test falliti, non lo sei usando il test di regressione nel modo giusto. La suite di test dovrebbe superare tutti i test prima di pubblicare il codice.

L'unico motivo valido per saltare i test è se testano funzionalità incomplete e impiegano una quantità eccessiva di tempo che potresti impiegare meglio durante l'implementazione della cosa che dovrebbero testare. (Questo è solo un problema se non si pratica uno sviluppo rigoroso guidato dai test, ma dopo tutto è una scelta valida.)

Altrimenti, non preoccuparti di provare a trasformare la tua suite di test in un indicatore che ti dice esattamente cosa c'è che non va. Non sarà mai esatto e non dovrebbe essere. Dovrebbe proteggerti dal fare lo stesso errore due volte, tutto qui.


8

Dipende dai tuoi strumenti, ma probabilmente non puoi (e non dovresti)

Alcuni framework di unit test ( ad esempio PHPUnit ) consentono di "concatenare" i test in modo che un test fallito su un livello non esegua altri test. Tuttavia, dubito che ciò risolverà il tuo problema per questa situazione.

Non consentire l'esecuzione garantita dell'ordine di prova costringe i test a essere isolati l'uno dall'altro ed è generalmente considerato una buona cosa. Immagina cosa accadrebbe se i test non solo si eseguissero da soli, ma fornissero anche dati su cui altri test potrebbero funzionare ...

È possibile inserire questi metodi di utilità in una soluzione o categoria di test separata. Assicurati che si distinguano visivamente nel tuo test runner o che questa categoria venga eseguita per prima e non esegua altri test se i test in questa categoria falliscono *. Quando uno di questi test fallisce, probabilmente l'errore si sovrapporrà a tutti i test e dovresti assicurarti che chiunque esegua i test sappia iniziare riparando prima questi test falliti. Lo stesso vale per i test unitari e i test di integrazione. Se un Unittest fallisce, si collegherà in cascata e causerà ogni sorta di caos nei test di integrazione. Tutti sanno che quando i test di Unit AND Integration falliscono, si inizia controllando gli Unittests ...

* Con uno script di build o test automatizzato è possibile eseguire prima questa categoria, controllare il risultato ed eseguire gli altri test solo se questo primo batch di test viene superato.


5

Prova a mantenere atomico il tuo test unitario. Ricorda che anche il codice di test automatizzato fa parte della tua base di codice, ma di per sé non è in fase di test, quindi mantienilo il più semplice ed evidente possibile.

Per rispondere alla tua domanda in modo più diretto, non esiste alcuna garanzia dell'ordine di esecuzione dei test, quindi non esiste alcun modo per garantire che il test di utilità abbia esito positivo prima che vengano eseguiti gli altri test. Quindi non esiste un modo garantito per ottenere ciò che desideri pur avendo un'unica suite di test per tutti i tuoi test.

È possibile spostare i programmi di utilità nella propria soluzione e aggiungere un riferimento alla relativa dll risultante nel progetto corrente.


4

In un riepilogo non si desidera utilizzare strumenti / tecniche per fare cose diverse da quelle per cui sono destinate.

Quello che stai cercando di fare sembra una preoccupazione che potrebbe essere risolta facilmente con una pratica CI (integrazione continua).

In questo modo è possibile mantenere atomici i test come già suggerito e lasciare che l'IC si occupi della verifica dei test.

Se qualche test fallisce, puoi impostarlo in modo che non consenta al tuo codice di essere pubblicato.


4

Ho l'abitudine di provare sempre a differenziare il codice a livello di applicazione dal codice a livello di framework, quindi ho riscontrato il problema che stai descrivendo abbastanza spesso: di solito vuoi testare tutto il codice a livello di framework prima che qualsiasi codice a livello di applicazione inizi a essere testato . Inoltre, anche all'interno del codice a livello di framework, ci sono alcuni moduli di framework fondamentali che vengono utilizzati da tutti gli altri moduli di framework e, se qualcosa non funziona nei fondamenti, non ha davvero senso provare qualcos'altro.

Sfortunatamente, i fornitori di framework di test tendono ad avere idee un po 'rigide su come le loro creazioni devono essere utilizzate e sono piuttosto protettive di tali idee, mentre le persone che usano i loro framework tendono ad accettare l'uso previsto senza mettere in discussione. Questo è problematico, perché soffoca la sperimentazione e l'innovazione. Non conosco tutti gli altri, ma preferirei avere la libertà di provare a fare qualcosa in modo strano e vedere di persona se i risultati sono migliori o peggiori di quelli stabiliti, piuttosto che non avere la libertà di fare le cose a modo mio in primo luogo.

Quindi, a mio avviso, le dipendenze dei test sarebbero una cosa meravigliosa da avere, e al posto di ciò, la possibilità di specificare l'ordine in cui verranno eseguiti i test sarebbe la cosa migliore da fare.

L'unico modo che ho trovato per affrontare il problema dei test di ordinamento è quello di nominare con cura, in modo da sfruttare la tendenza dei framework di test per eseguire i test in ordine alfabetico.

Non so come funziona in Visual Studio, perché non ho ancora fatto nulla che implichi test approfonditi con C #, ma nella parte Java del mondo funziona come segue: Nella cartella di origine di un progetto di solito abbiamo due sottocartelle, uno chiamato "main", contenente il codice di produzione e uno chiamato "test", contenente il codice di test. Sotto "main" abbiamo una gerarchia di cartelle che corrisponde esattamente alla gerarchia dei pacchetti del nostro codice sorgente. I pacchetti Java corrispondono approssimativamente agli spazi dei nomi C #. C # non richiede di abbinare la gerarchia di cartelle alla gerarchia dello spazio dei nomi, ma è consigliabile farlo.

Ora, ciò che le persone di solito fanno nel mondo Java è che nella cartella "test" rispecchiano la gerarchia di cartelle che si trova nella cartella "main", in modo che ogni test risieda nello stesso pacchetto esatto della classe che verifica. La logica alla base di ciò è che molto spesso la classe testing deve accedere ai membri del pacchetto privato della classe sotto test, quindi la classe testing deve trovarsi nello stesso pacchetto della classe sotto test. Nel lato C # del mondo non esiste qualcosa come la visibilità locale dello spazio dei nomi, quindi non c'è motivo di rispecchiare le gerarchie di cartelle, ma penso che i programmatori C # seguano più o meno la stessa disciplina nella strutturazione delle loro cartelle.

In ogni caso, trovo tutta questa idea di consentire alle classi di test di avere accesso ai membri del pacchetto locale delle classi sotto test errate, perché tendo a testare interfacce, non implementazioni. Pertanto, la gerarchia di cartelle dei miei test non deve rispecchiare la gerarchia di cartelle del mio codice di produzione.

Quindi, quello che faccio è nominare le cartelle (ovvero i pacchetti) dei miei test come segue:

t001_SomeSubsystem
t002_SomeOtherSubsystem
t003_AndYetAnotherSubsystem
...

Ciò garantisce che tutti i test per "SomeSubsystem" verranno eseguiti prima di tutti i test per "SomeOtherSubsystem", che a loro volta verranno eseguiti prima di tutti i test per "AndYetAnotherSubsystem", e così via, e così via.

All'interno di una cartella, i singoli file di test sono denominati come segue:

T001_ThisTest.java
T002_ThatTest.java
T003_TheOtherTest.java

Naturalmente, è di grande aiuto che gli IDE moderni dispongano di potenti capacità di refactoring che consentano di rinominare interi pacchetti (e tutti i sotto-pacchetti e tutto il codice che li fa riferimento) con solo un paio di clic e sequenze di tasti.


2
I don't know about everyone else, but I would prefer to have the freedom to try to do something in an odd way, and see for myself whether the results are better or worse++ compagno. Non so che mi piace la soluzione, ma mi piace l'atteggiamento che hai mostrato lì.
RubberDuck,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.