È una cattiva pratica applicare un ordine di esecuzione per i test unitari?


84

Sto scrivendo test per un progetto che consiste in più sottomoduli. Ogni caso di test che ho scritto viene eseguito indipendentemente l'uno dall'altro e cancello tutti i dati tra i test.

Anche se i test vengono eseguiti in modo indipendente, sto prendendo in considerazione l'esecuzione di un ordine di esecuzione, poiché alcuni casi richiedono più di un sottomodulo. Ad esempio, un sottomodulo sta generando dati e un altro sta eseguendo query sui dati. Se il sottomodulo che genera i dati contiene un errore, anche il test per il sottomodulo di query fallirà, anche se il sottomodulo stesso funziona correttamente.

Non riesco a lavorare con dati fittizi, poiché la funzionalità principale che sto testando è la connessione a un server remoto black box, che ottiene solo i dati dal primo sottomodulo.

In questo caso, è corretto applicare un ordine di esecuzione per i test o è una cattiva pratica? Sento che c'è un odore in questa configurazione, ma non riesco a trovare un modo migliore per aggirare.

modifica: la domanda è da Come strutturare i test in cui un test è impostato da un altro test? poiché il test "precedente" non è un'installazione, ma verifica il codice che esegue l'installazione.



123
Se stai testando la connessione a un server remoto, per definizione non sono test unitari.
Telastyn,

9
La prima risposta mi ha confuso qui perché nel tuo titolo hai detto "È una cattiva pratica?" e nel riassunto della tua domanda hai scritto "va bene?" Chiunque risponda sì o no confonderà uno di quelli!
Liath

8
Sembra che tu stia creando una serie di test di integrazione. Anche per quello un test non dovrebbe fare affidamento su altri test.
Low Flying Pelican

17
Se l'ordine conta, probabilmente stai sbagliando.
Mark Rogers,

Risposte:


236

Non riesco a lavorare con dati fittizi, poiché la funzionalità principale che sto testando è la connessione a un server remoto black box, che ottiene solo i dati dal primo sottomodulo.

Questa è la parte chiave per me. Puoi parlare di "unit test" e loro "in esecuzione indipendentemente l'uno dall'altro", ma sembrano tutti che dipendono da questo server remoto e dipendono dal "primo sottomodulo". Quindi tutto sembra strettamente accoppiato e dipendente dallo stato esterno. Pertanto, stai scrivendo test di integrazione. Far eseguire questi test in un ordine specifico è abbastanza normale poiché dipendono fortemente da fattori esterni. Un'esecuzione di test ordinata, con la possibilità di uscire anticipatamente dall'esecuzione di test in caso di problemi, è perfettamente accettabile per i test di integrazione.

Ma varrebbe anche la pena dare un'occhiata alla struttura della tua app. Essere in grado di deridere il primo sottomodulo e il server esterno consentirebbe potenzialmente di scrivere veri test unitari per tutti gli altri sottomoduli.


14
Per non parlare del fatto che alcuni test devono verificare specificamente che il comportamento previsto si verifichi quando il server remoto non è disponibile.
Alexander

2
O, forse, hai intenzione di scrivere test di integrazione, e quindi deridere i dati non otterrà ciò che stai cercando di realizzare con questi test.
Guy Schalnat,

10
È molto probabile che Junit abbia "unità" nel suo nome.
Thorbjørn Ravn Andersen,

7
@ ThorbjørnRavnAndersen Esattamente. Le persone scrivono naturalmente test di integrazione, piuttosto che test unitari, poiché i test di integrazione sono entrambi molto più utili e molto meno difficili da scrivere rispetto ai test di unità "reali". Ma poiché i popolari framework di test prendono il nome dal concetto di unit test, il termine è stato cooptato e significa "qualsiasi test automatizzato" nel linguaggio moderno.
Mason Wheeler,

1
@MasonWheeler O anche cooptato da gestori non tecnici per indicare i test di accettazione.
TKK,

32

Sì, è una cattiva pratica.

Generalmente, un test unitario ha lo scopo di testare una singola unità di codice (ad esempio una singola funzione basata su uno stato noto).

Quando si desidera testare una catena di eventi che potrebbero verificarsi in natura, si desidera uno stile di prova diverso, ad esempio un test di integrazione. Questo è ancora più vero se si dipende da un servizio di terze parti.

Per testare le cose in questo modo, è necessario trovare un modo per iniettare i dati fittizi, ad esempio implementando un'interfaccia del servizio dati che rispecchia la richiesta Web ma restituisce dati noti da un file di dati fittizi locale.


8
Concordato. Penso che questa confusione derivi dal fatto che molte persone hanno l'idea che i test di integrazione debbano essere end-to-end e che usano "unit test" per fare riferimento a qualsiasi test che testa solo uno strato .
autofago

8
@autophage: sono assolutamente d'accordo con questo. In effetti sono così d'accordo che mi ritrovo regolarmente a cadere nella stessa trappola nonostante sia d'accordo che si tratti di una trappola 😂
Lightness Races in Orbit

16

L'ordine di esecuzione forzata che proponi ha senso solo se interrompi anche l'esecuzione del test dopo il primo errore.

Annullare l'esecuzione del test al primo errore significa che ogni test può scoprire solo un singolo problema e non può trovare nuovi problemi fino a quando tutti i problemi precedenti non sono stati risolti. Se il primo test da eseguire rileva un problema che richiede un mese per essere risolto, durante quel mese effettivamente nessun test verrà eseguito.

Se non si interrompe l'esecuzione del test al primo errore, l'ordine di esecuzione forzata non ti acquista nulla perché ogni test non riuscito deve essere esaminato comunque. Anche solo per confermare che il test sul sottomodulo di query non riesce a causa dell'errore identificato anche sul sottomodulo di generazione dei dati.

Il miglior consiglio che posso dare è di scrivere i test in modo che sia facile identificare quando un fallimento in una dipendenza sta causando il fallimento del test.


7

L'odore a cui ti riferisci è l'applicazione di una serie errata di vincoli e regole ai tuoi test.

I test unitari vengono spesso confusi con i "test automatici" o "test automatizzati di un programmatore".

I test delle unità devono essere piccoli, indipendenti e veloci.

Alcune persone leggono erroneamente questo come "i test automatici scritti da un programmatore devono essere piccoli indipendenti e veloci" . Significa semplicemente che se i tuoi test non sono piccoli, indipendenti e veloci, non sono Test di unità, e quindi alcune delle regole per Test di unità non dovrebbero, non possono o non devono applicarsi ai tuoi test. Un esempio banale: dovresti eseguire i test delle unità dopo ogni build, cosa che non devi fare per i test automatici che non sono veloci.

Sebbene i tuoi test non siano Test unitari, significa che puoi saltare una regola e avere l'interdipendenza tra i test, ma hai anche scoperto che ci sono altre regole che potresti aver perso e che dovrai reintrodurre - qualcosa per lo scopo di un'altra domanda .


6

Come notato sopra, quello che stai eseguendo sembra essere un test di integrazione, tuttavia dichiari che:

Ad esempio, un sottomodulo sta generando dati e un altro sta eseguendo query sui dati. Se il sottomodulo che genera i dati contiene un errore, anche il test per il sottomodulo di query fallirà, anche se il sottomodulo stesso funziona correttamente.

E questo potrebbe essere un buon posto per iniziare il refactoring. Il modulo che esegue query sui dati non dovrebbe dipendere da un'implementazione concreta del primo modulo (generazione di dati). Invece sarebbe meglio iniettare un'interfaccia contenente i metodi per arrivare a quei dati e questo può quindi essere deriso per testare le query.

per esempio

Se hai:

class Queries {

    int GetTheNumber() {
        var dataModule = new Submodule1();
        var data = dataModule.GetData();
        return ... run some query on data
    }
}

Preferisco invece:

interface DataModule {
    Data GetData();
}


class Queries {

    IDataModule _dataModule;

    ctor(IDataModule dataModule) {
       _dataModule = dataModule;
    }

    int GetTheNumber() {
        var data = _dataModule.GetData();
        return ... run some query on data
    }
}

Ciò rimuove la dipendenza dalle query sull'origine dati e consente di impostare test di unità facilmente ripetibili per scenari particolari.


6

Le altre risposte menzionano che i test di ordinazione sono errati (il che è vero per la maggior parte del tempo), ma c'è un buon motivo per far rispettare l'ordine nell'esecuzione dei test: assicurarsi che i test lenti (ovvero i test di integrazione) vengano eseguiti dopo i test più veloci (test che non si basano su altre risorse esterne). In questo modo è possibile eseguire più test più rapidamente, accelerando il ciclo di feedback.


2
Sarei più propenso a indagare sul motivo per cui un certo test unitario sta funzionando lentamente anziché applicare un ordine. I test unitari dovrebbero essere veloci.
Robbie Dee,

L'OP afferma di non poter lavorare con dati fittizi per alcuni di questi test. Ciò significa che un hit del database di qualche tipo, rallenta tutti i test (anche alcuni test unitari reali che dovrebbero essere eseguiti velocemente in modo naturale). Se ha altri test che non richiedono hit del database, eseguiranno un ordine di grandezza più veloce di qualsiasi cosa richieda hit del disco o della rete.
Mike Holler,

2
Hai ragione entrambe, penso; Robbie ha ragione sul fatto che i test unitari dovrebbero essere piccoli, veloci e isolati dalle dipendenze, quindi l'ordine non dovrebbe avere importanza e l'ordinamento casuale spesso incoraggia una migliore progettazione rafforzando tale indipendenza; e Mike ha ragione nel dire che eseguire prima i test più veloci è molto, molto buono per i test di integrazione . Come nelle risposte sopra, parte del problema è la terminologia dei test unitari e di integrazione.
WillC

@MikeHoller Quindi non sono test unitari. Non dovrebbe esserci alcuna confusione su cosa siano i test unitari .
Robbie Dee,

@RobbieDee Stavo semplicemente usando la terminologia utilizzata dall'OP. Capisco che questi non sono veri test unitari. Se vuoi combattere sulla terminologia, presentalo con OP. (quindi perché ho chiarito con "test unitari reali" nel mio commento precedente ")
Mike Holler,
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.