Catalogo Anti-pattern di unit testing


203

anti-pattern : devono essere presenti almeno due elementi chiave per distinguere formalmente un effettivo anti-pattern da una semplice cattiva abitudine, cattiva pratica o cattiva idea:

  • Qualche modello ripetuto di azione, processo o struttura che inizialmente sembra essere benefico, ma che alla fine produce conseguenze più negative che risultati benefici, e
  • Una soluzione refactored che è chiaramente documentata, provata nella pratica e ripetibile.

Vota per l'anti-pattern TDD che hai visto "in the wild" una volta di troppo.
Il post sul blog di James Carr e la discussione correlata su yahoogroup di testdrivendevelopment

Se ne hai trovato uno "senza nome" ... pubblicalo anche tu. Un post per anti-pattern, per favore, perché i voti contino qualcosa.

Il mio interesse è quello di trovare il sottoinsieme top-n in modo che possa discuterne in un incontro al sacco nel prossimo futuro.


Aaron, sembra che tu sia tutto su questo :) Sarebbe una buona idea aggiungere le tag-line o gli slogan come commenti in modo che possiamo avere meno scrolling .. che dire?
Gishu

1
Sta venendo fuori piuttosto bene .. grazie ragazzi n ragazze. Continua a farli venire .. uno dei post SO più informativi IMHO
Gishu

2
+1 adoro questo thread !!! E la maggior parte di questi sono così veri e anche prevalenti!
Chii

Bel thread, perché questa community wiki però ???
Quibblesome

2
Perché è una specie di sondaggio - non vorresti raccogliere rappresentante solo perché hai pubblicato il tipo più comune di anti-pattern;)
Gishu

Risposte:


70

Cittadini di seconda classe : il codice di test non è ben rifattorizzato come il codice di produzione, contenente molto codice duplicato, rendendo difficile mantenere i test.


67

The Free Ride / Piggyback - James Carr, Tim Ottinger
Piuttosto che scrivere un nuovo metodo di test case per testare un'altra / caratteristica / funzionalità distinta , una nuova asserzione (e le sue azioni corrispondenti, ad esempio, Act steps from AAA) cavalca in un test case esistente .


15
Sì, è il mio preferito. Lo faccio tutto il tempo. Oh ... aspetta ... hai detto che questa era una brutta cosa. :-)
guidoismo

1
Non sono così sicuro che questo sia un anti-pattern. Tutti gli invarianti devono essere truedopo ogni possibile chiamata del mutatore. Quindi vorrai controllare che ogni invariante sia truedopo ogni combinazione di mutatore e dati di input che stai testando. Ma vorrai ridurre la duplicazione e assicurarti di controllare tutte le invarianti, comprese quelle che attualmente non causano errori di test. Quindi li metti tutti in una checkInvariants()funzione di verifica e la usi in ogni test. Il codice cambia e viene aggiunto un altro invariante. Lo metti anche nella funzione, ovviamente. Ma è un freerider.
Raedwald

2
@ Raedwald - Nel tempo, il nome del test non corrisponde più a tutte le cose che verifica. Inoltre hai qualche difficoltà a causa di test intrecciati; un guasto non indica la causa esatta del guasto. ad es. un esempio canonico di questo test leggerebbe qualcosa come Opaque Superset di tutti i passaggi di Arrange >> Act >> Assert A >> Agisci ancora >> Assert B >> Agisci ancora >> Assert C.Ora idealmente se A e C sono rotto, dovresti vedere 2 test falliti. Con il test sopra, ne vedresti solo uno, quindi aggiusti A e alla prossima esecuzione, ti direbbe che ora C è rotto. ora immagina 5-6 prove distinte fuse insieme ..
Gishu

1
"il nome del test non corrisponde più a tutte le cose che verifica" Solo se il test è denominato in base alla condizione del post che era originariamente presente. Se si nomina per la combinazione di nome-metodo, stato di configurazione e dati di input (argomenti del metodo), non ci sono problemi.
Raedwald

"un errore non indica la causa esatta dell'errore" nessun errore di asserzione indica mai la causa di un errore. Ciò richiede un po 'di approfondimento nei dettagli di implementazione: debug per un errore di regressione, la tua conoscenza dello stato di sviluppo per alcuni lavori TDD.
Raedwald

64

Buon percorso

Il test rimane su percorsi felici (cioè risultati attesi) senza testare limiti ed eccezioni.

JUnit Antipatterns


Causa: o vincoli di tempo esagerati o palese pigrizia. Soluzione modificata: dedica un po 'di tempo a scrivere più test per eliminare i falsi positivi. Quest'ultima causa ha bisogno di una frusta. :)
Spoike

59

L'eroe locale

Un test case che dipende da qualcosa di specifico dell'ambiente di sviluppo su cui è stato scritto per essere eseguito. Il risultato è che il test supera le scatole di sviluppo, ma fallisce quando qualcuno tenta di eseguirlo altrove.

La dipendenza nascosta

Strettamente correlato all'eroe locale, un test unitario che richiede che alcuni dati esistenti siano stati popolati da qualche parte prima che il test venga eseguito. Se quei dati non sono stati popolati, il test fallirà e lascerà poche indicazioni allo sviluppatore su cosa voleva, o perché ... costringendolo a scavare attraverso acri di codice per scoprire da dove avrebbero dovuto provenire i dati che stava usando.


Purtroppo visto fin troppe volte con le antiche .dll che dipendono da file .ini nebulosi e variegati che sono costantemente fuori sincronia su un dato sistema di produzione, per non parlare di quelli esistenti sulla tua macchina senza una consultazione approfondita con i tre sviluppatori responsabili di quelle DLL. Sospiro.


Questo è un bell'esempio dell'acronimo dello sviluppatore WOMPC. "Funziona sul mio PC!" (di solito si dice per toglierti i tester).
Joris Timmermans

58

Chain Gang

Un paio di test che devono essere eseguiti in un certo ordine, cioè un test cambia lo stato globale del sistema (variabili globali, dati nel database) e il test successivo dipende da esso.

Lo vedi spesso nei test del database. Invece di eseguire un rollback teardown(), i test eseguono il commit delle modifiche nel database. Un'altra causa comune è che le modifiche allo stato globale non sono racchiuse in blocchi try / latest che vengono puliti se il test fallisce.


questo è semplicemente brutto .. Le interruzioni dei test devono essere nozioni indipendenti. Ma l'ho letto in più posti .. immagino che il 'popolare TDD' sia piuttosto incasinato
Gishu

56

La
beffa A volte prendere in giro può essere utile e utile. Ma a volte gli sviluppatori possono perdere se stessi e nel loro sforzo di deridere ciò che non viene testato. In questo caso, uno unit test contiene così tanti mock, stub e / o falsi che il sistema sotto test non viene nemmeno testato, invece i dati restituiti dai mock sono ciò che viene testato.

Fonte: post di James Carr.


2
Credo che la causa sia che la tua classe sottoposta a test ha troppe dipendenze. Un'alternativa modificata consiste nell'estrarre il codice che può essere isolato.
Spoike

@Spoike; Se ti trovi in ​​un'architettura a più livelli, ciò dipende davvero dal ruolo della classe; alcuni livelli tendono ad avere più dipendenze di altri.
krosenvold

Ho visto di recente, in un blog rispettato, la creazione di una configurazione di entità fittizia da restituire da un repository fittizio. WTF? Perché non creare un'istanza di un'entità reale in primo luogo. Per quanto mi riguarda, sono appena stato bruciato da un'interfaccia derisa in cui la mia implementazione lanciava NotImplementedExceptions tutt'intorno.
Thomas Eyde,

40

The Silent Catcher - Kelly?
Un test che passa se viene lanciata un'eccezione .. anche se l'eccezione che si verifica effettivamente è diversa da quella prevista dallo sviluppatore.
Vedi anche: Secret Catcher

[Test]
[ExpectedException(typeof(Exception))]
public void ItShouldThrowDivideByZeroException()
{
   // some code that throws another exception yet passes the test
}

Quello è complicato e pericoloso (cioè ti fa pensare di aver testato un codice che esplode sempre ogni volta che viene eseguito). Ecco perché cerco di essere specifico sia su una classe di eccezione che su qualcosa di unico all'interno del messaggio.
Joshua Cheek

34

L'ispettore
Un test unitario che viola l'incapsulamento nel tentativo di ottenere una copertura del codice del 100%, ma sa così tanto su cosa sta succedendo nell'oggetto che qualsiasi tentativo di refactoring interromperà il test esistente e richiederà che qualsiasi modifica si rifletta nell'unità test.


'come faccio a testare le mie variabili membro senza renderle pubbliche ... solo per test di unità?'


2
Causa: dipendenza assurda dal test white box. Esistono strumenti per generare questo tipo di test come Pex su .NET. Soluzione modificata: prova invece il comportamento e se hai davvero bisogno di controllare i valori limite, lascia che gli strumenti automatici generino il resto.
Spoike

1
Prima che Moq venisse in giro, ho dovuto abbandonare i quadri beffardi a favore della scrittura a mano dei miei mock. Era troppo facile legare i miei test all'implementazione effettiva, rendendo quasi impossibile qualsiasi refactoring. Non riesco a capire la differenza, a parte Moq, raramente faccio questo tipo di errori.
Thomas Eyde

34

Configurazione eccessiva - James Carr
Un test che richiede una configurazione enorme per iniziare anche il test. A volte vengono utilizzate diverse centinaia di righe di codice per preparare l'ambiente per un test, con diversi oggetti coinvolti, il che può rendere difficile accertare realmente cosa viene testato a causa del "rumore" di tutte le impostazioni in corso. (Src: post di James Carr )


Capisco che un'impostazione di test eccessiva di solito punta a a) codice mal strutturato o b) derisione insufficiente, corretto?
Topher Hunt

Bene, ogni situazione potrebbe essere diversa. Potrebbe essere dovuto a un accoppiamento elevato. Ma di solito è un caso di specificazione eccessiva, specificando (false aspettative) ogni singolo collaboratore nello scenario: questo accoppia il test all'implementazione e li rende fragili. Se la chiamata al collaboratore è un dettaglio incidentale del test, non dovrebbe essere nel test. Questo aiuta anche a mantenere il test breve e leggibile.
Gishu

32

Sonda anale

Un test che deve usare modi folli, illegali o comunque malsani per svolgere il suo compito come: leggere campi privati ​​usando setAccessible di Java (true) o estendere una classe per accedere a campi / metodi protetti o dover mettere il test in un determinato pacchetto per accedere pacchetti / metodi globali.

Se vedi questo modello, le classi sotto test usano troppi dati nascosti.

La differenza tra questo e The Inspector è che la classe sotto test cerca di nascondere anche le cose che devi testare. Quindi il tuo obiettivo non è ottenere una copertura del test del 100%, ma essere in grado di testare qualsiasi cosa. Pensa a una classe che ha solo campi privati, un run()metodo senza argomenti e nessun getter. Non c'è modo di testarlo senza infrangere le regole.


Commento di Michael Borgwardt: Questo non è davvero un antipattern di test, è pragmatismo affrontare le carenze nel codice in fase di test. Ovviamente è meglio correggere queste carenze, ma potrebbe non essere possibile nel caso di librerie di terze parti.

Aaron Digulla: Sono d'accordo. Forse questa voce è davvero più adatta per un wiki "JUnit HOWTO" e non per un antipattern. Commenti?


non è lo stesso dell'ispettore?
Gishu

1
Hmm .. questa frase "la classe sottoposta a test cerca di nascondere anche le cose che devi testare" indica una lotta di potere tra la classe e il test. Se dovrebbe essere testato .. dovrebbe essere pubblicamente raggiungibile in qualche modo .. tramite il comportamento di classe / interfaccia .. questo in qualche modo puzza di incapsulamento in violazione
Gishu

2
npellow: Maven2 ha un plugin per questo, non è vero?
Aaron Digulla

1
Questo non è davvero un antipattern di test, è pragmatismo affrontare le carenze nel codice che viene testato. Ovviamente è meglio correggere queste carenze, ma potrebbe non essere possibile nel caso di librerie di terze parti.
Michael Borgwardt

1
IDK, deve avere una sorta di effetto collaterale. Testerei l'effetto collaterale. Non sono sicuro di cosa intendi per testare l'API di terze parti, direi che dovresti racchiuderlo nel tuo codice che puoi testare è stato utilizzato correttamente, quindi l'integrazione testare quel codice contro l'API di terze parti. Non testerebbe il codice di terze parti.
Joshua Cheek il

26

Il test senza nome - Nick Pellow

Il test che viene aggiunto per riprodurre un bug specifico nel bug tracker e il cui autore ritiene non garantisca un nome proprio. Invece di migliorare un test esistente e mancante, viene creato un nuovo test chiamato testForBUG123.

Due anni dopo, quando il test fallisce, potresti dover prima provare a trovare BUG-123 nel tuo bug tracker per capire l'intento del test.


7
Così vero. Anche se questo è leggermente più utile di un test chiamato "TestMethod"
NikolaiDante

8
a meno che il bugtracker non cambi, e perdi il vecchio tracker e i suoi identificatori del problema ... quindi PROJECT-123 non significa più nulla ...
Chii

25

Lo Slow Poke

Uno unit test incredibilmente lento. Quando gli sviluppatori danno il via, hanno il tempo di andare in bagno, prendere una sigaretta o, peggio, dare il via al test prima di tornare a casa alla fine della giornata. (Src: post di James Carr )

ovvero i test che non verranno eseguiti con la frequenza necessaria


Alcuni test vengono eseguiti lentamente per loro stessa natura. Se decidi di non eseguirli tanto spesso quanto gli altri, assicurati che vengano eseguiti almeno su un server CI il più spesso possibile.
Chris Vest

Questa è una domanda ovvia, ma quali sono i modi più generali per risolvere questo problema?
Topher Hunt

Questo inizialmente sembra vantaggioso, eh?
Kev

1
@TopherHunt In genere i test sono lenti perché hanno alcune dipendenze costose (cioè filesystem, database). Il trucco è analizzare le dipendenze fino a quando non vedi il problema, quindi spingere la dipendenza verso l'alto nello stack di chiamate. Ho scritto un caso di studio in cui i miei studenti hanno portato la loro suite di test unitari da 77 secondi a 0,01 secondi correggendo le loro dipendenze: github.com/JoshCheek/fast_tests
Joshua Cheek

20

La farfalla

Devi testare qualcosa che contiene dati che cambiano continuamente, come una struttura che contiene la data corrente, e non c'è modo di inchiodare il risultato a un valore fisso. La parte brutta è che non ti interessa affatto questo valore. Rende solo il tuo test più complicato senza aggiungere alcun valore.

Il pipistrello della sua ala può provocare un uragano dall'altra parte del mondo. - Edward Lorenz, L'effetto farfalla


Qual è l'anti-pattern qui: che aspetto ha un test come questo? C'è una soluzione? C'è qualche vantaggio discutibile nel codice sottoposto a test per escludere una dipendenza come System.DateTime.Now, oltre ad avere test unitari più semplici o deterministici?
Merlyn Morgan-Graham

1
In Java, un esempio potrebbe essere chiamare toString()un oggetto che non sovrascrive il metodo. Questo ti darà l'ID dell'oggetto che dipende dall'indirizzo di memoria. Oppure toString()contiene la chiave primaria dell'oggetto e questa cambia ogni volta che esegui il test. Ci sono tre modi per risolvere questo problema: 1. Modificare il codice che si sta testando, 2. utilizzare regexp per rimuovere le parti variabili dei risultati del test o 3. utilizzare strumenti potenti per sovrascrivere i servizi di sistema in modo che restituiscano risultati prevedibili.
Aaron Digulla

La causa alla base di questo anti-pattern è che il codice sotto test non si preoccupa di quanto sforzo potrebbe essere per testarlo. Quindi il capriccio di uno sviluppatore è l'ala della farfalla che causa problemi altrove.
Aaron Digulla

19

The Flickering Test (Fonte: Romilly Cocking)

Un test che solo occasionalmente fallisce, non in momenti specifici, ed è generalmente dovuto alle condizioni di gara all'interno del test. In genere si verifica durante il test di qualcosa che è asincrono, come JMS.

Forse un super set di anti-pattern " Wait and See " e " The Sleeper ".

La compilazione non è riuscita, vabbè, esegui di nuovo la compilazione. - Sviluppatore anonimo


@Stuart - un video da non perdere che descrive questo è "Auto bloccata - Prova ora!" videosift.com/video/… Questo pattern potrebbe anche essere chiamato "Try Now!", o semplicemente - "The Flakey Test"
npellow

1
Una volta ho scritto un test per un PRGN che garantiva una corretta distribuzione. Occasionalmente, falliva a caso. Vai a capire. :-)
Chris Vest

1
Non sarebbe un buon test da fare? Se un test fallisce, è necessario individuare l'origine del problema. Ho litigato con qualcuno per un test fallito tra le 9 e mezzanotte. Ha detto che era casuale / intermittente. Alla fine è stato fatto risalire a un bug relativo ai fusi orari. Vai a capire.
Trenton

@Christian Vest Hansen: non potresti seminare?
Andrew Grimm

@trenton È solo un buon test da fare se gli sviluppatori possono essere disturbati a rintracciarlo, invece di ignorarlo (cosa con cui possono farla franca, poiché passa la maggior parte del tempo).
Will Sheppard

19

Aspetta e vedi

Un test che esegue un codice di configurazione e quindi deve "attendere" un determinato periodo di tempo prima di poter "vedere" se il codice sottoposto a test ha funzionato come previsto. Un testMethod che utilizza Thread.sleep () o equivalente è sicuramente un test "Wait and See".

In genere, potresti vederlo se il test sta testando un codice che genera un evento esterno al sistema come un'e-mail, una richiesta http o scrive un file su disco.

Tale test può anche essere un eroe locale poiché fallirà se eseguito su una scatola più lenta o su un server CI sovraccarico.

L'anti-pattern Wait and See non deve essere confuso con The Sleeper .


Hmm .. beh io uso qualcosa del genere. in quale altro modo potrei testare il codice multi-thread?
Gishu

@ Gishu, vuoi davvero testare più thread in esecuzione contemporaneamente? Provo solo a testare l'unità qualunque cosa il metodo run () fa in isolamento. Un modo semplice per farlo è chiamare run () - che bloccherà, invece di start () dallo unit test.
npellow

@Gishu usa CountDownLatches, Semaphores, Conditions o simili, per fare in modo che i thread si dicano quando possono passare al livello successivo.
Chris Vest

Un esempio: madcoderspeak.blogspot.com/2008/11/… Brew button evt. L'osservatore esegue il polling a intervalli e genera eventi modificati .. nel qual caso aggiungo un ritardo in modo che i thread di polling abbiano la possibilità di essere eseguiti prima che il test termini.
Gishu

Penso che il collegamento del fumetto sia interrotto.
Andrew Grimm

17

Dispositivo condiviso in modo inappropriato - Tim Ottinger
Diversi casi di test nel dispositivo di prova non usano nemmeno o necessitano della configurazione / smontaggio. In parte a causa dell'inerzia dello sviluppatore nel creare un nuovo dispositivo di prova ... è più facile aggiungere un altro caso di prova alla pila


1
Può anche darsi che la classe sottoposta a test stia cercando di fare troppo.
Mike Two

16

Il gigante

Uno unit test che, sebbene stia testando validamente l'oggetto in prova, può estendersi su migliaia di righe e contenere molti molti casi di test. Questo può essere un indicatore che il sistema sottoposto a test è un oggetto divino (post di James Carr).

Un segno sicuro per questo è un test che si estende su più di poche righe di codice. Spesso, il test è così complicato che inizia a contenere bug propri o di comportamento instabile.


15

Ci crederò quando vedrò alcune GUI lampeggianti
Una fissazione / ossessione malsana per testare l'app tramite la sua GUI `` proprio come un vero utente ''

Testare le regole aziendali tramite la GUI è una forma terribile di accoppiamento. Se scrivi migliaia di test attraverso la GUI e poi cambi la tua GUI, migliaia di test si interrompono.
Piuttosto, testare solo le cose della GUI attraverso la GUI e accoppiare la GUI a un sistema fittizio invece del sistema reale, quando si eseguono quei test. Testa le regole di business tramite un'API che non coinvolge la GUI. - Bob Martin

"Devi capire che vedere è credere, ma anche sapere che credere è vedere." - Denis Waitley


1
Se pensavi che le GUI lampeggianti fossero sbagliate, ho visto qualcuno che ha scritto un test jUnit che ha avviato la GUI e necessitava dell'interazione dell'utente per continuare. Ha impiccato il resto della suite di test. Questo per quanto riguarda l'automazione dei test!
Spoike

Non sono d'accordo. Testare le GUI è difficile, ma sono anche fonte di errori. Non testarli è solo pigro.
Ray

3
il punto qui è che non dovresti testare le GUI, ma piuttosto non dovresti testare solo tramite la GUI. È possibile eseguire test "senza testa" senza la GUI. Mantieni la GUI il più sottile possibile - usa un sapore di MVP - puoi quindi cavartela senza testarla affatto. Se ti accorgi di avere bug che si verificano continuamente nel sottile strato della GUI, coprilo con dei test .. ma la maggior parte delle volte, non trovo che ne valga la pena. Gli errori di "cablaggio" della GUI sono generalmente più facili da correggere ...
Gishu

@Spoike: i test manuali guidati non sono male, né l'uso di jUnit (o qualsiasi altro framework di unit test) per guidare test automatizzati che non siano unit test. Non dovresti semplicemente metterli nello stesso progetto, né trattarli come test unitari (es. Eseguire costantemente, o dopo ogni build).
Merlyn Morgan-Graham

1
@ MerlynMorgan-Graham Sono d'accordo, e non volevo dire che non dovresti testare la GUI. La convinzione dei membri del team che fosse giusto mescolare test manuali guidati con quelli automatici, mi disturbava. Ho scoperto in seguito che era un ottimo modo per convincere tutti coloro che non sono abituati a TDD a smettere di usarlo. Trovo che mescolare i test funzionali (che sono volatili) con i test unitari (che dovrebbero essere stabili) sia un male se vuoi seguire il processo TDD.
Spoike

14

The Sleeper, aka Mount Vesuvius - Nick Pellow

Un test che è destinato a fallire in un momento e in una data specifici in futuro. Ciò è spesso causato dal controllo dei limiti errati durante il test del codice che utilizza un oggetto Data o Calendario. A volte, il test potrebbe non riuscire se eseguito in un momento della giornata molto specifico, come mezzanotte.

"The Sleeper" non deve essere confuso con l' anti-pattern " Wait And See ".

Quel codice sarà stato sostituito molto prima del 2000 - Molti sviluppatori nel 1960


Preferirei chiamarlo un vulcano dormiente :) .. ma so di cosa stai parlando .. ad esempio una data scelta come data futura per un test al momento della scrittura diventerà una data presente / passata quando quella data passa .. rompendo la prova. Potresti postare un esempio .. solo per illustrare questo.
Gishu

@Gishu - +1. Stavo pensando la stessa cosa, ma non riuscivo a decidere tra i due. Ho aggiornato il titolo per renderlo un po 'più chiaro;)
npellow

11

L'albero morto

Un test in cui è stato creato uno stub, ma il test non è stato effettivamente scritto.

L'ho effettivamente visto nel nostro codice di produzione:

class TD_SomeClass {
  public void testAdd() {
    assertEquals(1+1, 2);
  }
}

Non so nemmeno cosa pensare al riguardo.


8
:) - noto anche come Process Compliance Backdoor.
Gishu

1
Ne abbiamo avuto un esempio di recente in un test e un metodo sottoposto a test che erano stati riformulati ripetutamente. Dopo alcune iterazioni, il test è diventato una chiamata al metodo sottoposto a test. E poiché il metodo ora è tornato vuoto, non c'erano affermazioni da affermare. Quindi, fondamentalmente, il test stava solo assicurandosi che il metodo non generasse un'eccezione. Non importa se ha effettivamente fatto qualcosa di utile o corretto. L'ho trovato nella revisione del codice e ho chiesto, "Allora ... cosa stiamo testando qui?"
Marvo

11

mi ha morso questo oggi:

Pavimento bagnato :
il test crea dati che sono persistenti da qualche parte, ma il test non viene pulito al termine. Ciò fa sì che i test (lo stesso test o forse altri test) non riescano nelle successive esecuzioni di test.

Nel nostro caso, il test ha lasciato un file in giro nella directory "temp", con i permessi dell'utente che ha eseguito il test la prima volta. Quando un utente diverso ha provato a eseguire il test sulla stessa macchina: boom. Nei commenti sul sito di James Carr, Joakim Ohlrogge si riferiva a questo come al "lavoratore sciatto", e faceva parte dell'ispirazione per "Generoso avanzi". Mi piace di più il mio nome (meno offensivo, più familiare).


È possibile utilizzare la regola delle cartelle temporanee di junit per evitare pavimenti bagnati.
DaveFar

Questo tipo si riferisce a un anti pattern di integrazione continua. In CI, ogni sviluppatore dovrebbe avere il proprio spazio di lavoro e le proprie risorse, e anche la macchina di costruzione dovrebbe essere il proprio ambiente. Quindi eviti cose come problemi di autorizzazione (o forse
finisci

11

The Cuckoo - Frank Carver
Un test unitario che si trova in un caso di test con molti altri e gode dello stesso processo di configurazione (potenzialmente lungo) degli altri test nel caso di test, ma poi elimina alcuni o tutti gli artefatti dal setup e crea il proprio.
Sintomo avanzato di: dispositivo condiviso in modo inappropriato


10

The Secret Catcher - Frank Carver
Un test che a prima vista sembra non essere testato, a causa dell'assenza di affermazioni. Ma "il diavolo è nei dettagli" .. il test si basa davvero su un'eccezione da lanciare e si aspetta che il framework di test catturi l'eccezione e la segnali all'utente come un errore.

[Test]
public void ShouldNotThrow()
{
   DoSomethingThatShouldNotThrowAnException();
}

2
Questo in effetti può essere un test valido, a mio parere, soprattutto come test di regressione.
Ilja Preuß

scusa di nuovo l'ho confuso con Silent catcher ... i test unitari dovrebbero indicare chiaramente l'intento su ciò che viene testato piuttosto che dire "questo dovrebbe funzionare" .. (+1 tp qualcosa è meglio di niente. specialmente se sei in regressione legacy paese)
Gishu

1
In questo tipo di test, almeno rilevo Eccezione e la assegno a una variabile. Quindi dichiaro per non nullo.
Thomas Eyde,

4
Alcuni framework hanno Assert.DoesNotThrow(SomeDelegateType act)un'asserzione di stile che può essere utilizzata specificamente in casi come questo. Lo trovo meno grossolano rispetto a un caso di test che ha esito positivo quando un costruttore restituisce non nullo, ma fallisce quando il costruttore lancia. Un costruttore non restituirà mai null. (Nota: si applica solo alle lingue in cui è garantito che un costruttore restituisca un valore non nullo)
Merlyn Morgan-Graham

10

Il vandalo ambientale

Un test "unitario" che per vari "requisiti" inizia a diffondersi nel suo ambiente, utilizzando e impostando variabili / porte di ambiente. L'esecuzione simultanea di due di questi test causerà eccezioni di "porta non disponibile", ecc.

Questi test saranno intermittenti e lasceranno gli sviluppatori a dire cose come "eseguilo di nuovo".

Una soluzione che ho visto è selezionare casualmente un numero di porta da utilizzare. Ciò riduce la possibilità di un conflitto, ma chiaramente non risolve il problema. Quindi, se puoi, prendi sempre in giro il codice in modo che non allochi effettivamente la risorsa non condivisibile.


@gcrain .. i test dovrebbero essere deterministici. IMO un approccio migliore sarebbe quello di utilizzare una porta "ben nota nel team" per i test e la pulizia prima e dopo il test correttamente in modo che sia sempre disponibile ...
Gishu

1
@gishu - il problema non è che non ci sono metodi setup () e teardown () per gestire l'utilizzo di queste porte. il problema è ad esempio l'esecuzione di un server CI e più versioni del test vengono eseguite contemporaneamente, tentando di utilizzare gli stessi numeri di porta hardcoded-in-the-test
gcrain

10

Il test di Turing

Un testcase generato automaticamente da uno strumento costoso che ha molte, molte affermazioni raccolte dalla classe sottoposta a test utilizzando un'analisi del flusso di dati troppo intelligente per metà. Induce gli sviluppatori in un falso senso di fiducia che il loro codice sia ben testato, assolvendoli dalla responsabilità di progettare e mantenere test di alta qualità. Se la macchina può scrivere i test per te, perché non può tirare fuori il dito e scrivere l'app stessa!

Ciao stupido. - Il computer più intelligente del mondo al nuovo apprendista (da un vecchio fumetto Amiga).


10

Il test del palo da quaranta piedi

Temendo di avvicinarsi troppo alla classe che stanno cercando di testare, questi test agiscono a distanza, separati da innumerevoli livelli di astrazione e migliaia di righe di codice dalla logica che stanno controllando. In quanto tali, sono estremamente fragili e suscettibili a tutti i tipi di effetti collaterali che si verificano durante il viaggio epico da e verso la classe di interesse.


9

Sosia

Per testare qualcosa, devi copiare parti del codice sotto test in una nuova classe con lo stesso nome e pacchetto e devi usare classpath magic o un classloader personalizzato per assicurarti che sia visibile per primo (quindi la tua copia viene scelta su).

Questo modello indica una quantità malsana di dipendenze nascoste che non puoi controllare da un test.

Ho guardato la sua faccia ... la mia faccia! Era come uno specchio ma mi ha congelato il sangue.


7

The Mother Hen - Frank Carver
Una configurazione comune che fa molto di più del necessario per i test case. Ad esempio creando tutti i tipi di strutture di dati complesse popolate con valori apparentemente importanti e unici quando i test affermano solo la presenza o l'assenza di qualcosa.
Sintomo avanzato di: dispositivo condiviso in modo inappropriato

Non so cosa fa ... Lo aggiungo comunque, per ogni evenienza. - Sviluppatore anonimo


7

La prova tutto

Non posso credere che questo non sia stato menzionato fino ad ora, ma i test non dovrebbero infrangere il principio di responsabilità unica .

Mi sono imbattuto in questo così tante volte, i test che infrangono questa regola sono per definizione un incubo da mantenere.


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.