Quanto beffardo è "giusto?"


10

Ho intitolato la domanda scherzosamente perché sono sicuro che "dipende", ma ho alcune domande specifiche.

Lavorando in un software che ha molti profondi livelli di dipendenza, il mio team si è abituato a deridere in modo abbastanza esteso per separare ciascun modulo di codice dalle dipendenze sottostanti.

Pertanto sono rimasto sorpreso dal fatto che Roy Osherove abbia suggerito in questo video che si dovrebbe usare beffardo solo qualcosa come il 5% delle volte. Immagino che siamo seduti da qualche parte tra il 70-90%. Di tanto in tanto ho visto anche altre indicazioni simili .

Dovrei definire quelle che considero due categorie di "test di integrazione" che sono così distinti che dovrebbero davvero avere nomi diversi: 1) Test in-process che integrano più moduli di codice e 2) Test out-of-process che parlano a database, file system, servizi web, ecc. È il tipo 1 di cui mi occupo, test che integrano più moduli di codice tutti in-process.

Gran parte della guida della comunità che ho letto suggerisce che dovresti preferire un gran numero di test unitari a grana fine isolati e un piccolo numero di test di integrazione end-to-end a grana grossa, perché i test unitari forniscono un feedback preciso esattamente dove le regressioni potrebbero essere state create, ma i test grossolani, che sono ingombranti da configurare, in realtà verificano più funzionalità end-to-end del sistema.

Detto questo, sembra necessario fare un uso piuttosto frequente del derisione per isolare queste unità di codice separate.

Dato un modello a oggetti come segue:

inserisci qui la descrizione dell'immagine

... Considera anche che la profondità di dipendenza della nostra applicazione va molto più in profondità di quanto potrei adattarmi in questa immagine, in modo che ci siano più livelli N tra il livello 2-4 e il livello 5-13.

Se voglio testare qualche semplice decisione logica presa nell'unità n. 1, e se ogni dipendenza viene iniettata dal costruttore nel modulo di codice che dipende da essa in modo tale, per esempio, che 2, 3 e 4 siano iniettati dal costruttore nel modulo 1 in l'immagine, preferirei piuttosto iniettare simulazioni di 2, 3 e 4 in 1.

Altrimenti, avrei bisogno di costruire istanze concrete di 2, 3 e 4. Questo può essere più difficile di una semplice digitazione extra. Spesso 2, 3 e 4 avranno requisiti di costruzione che possono essere difficili da soddisfare e secondo il grafico (e secondo la realtà del nostro progetto), dovrò costruire istanze concrete di N fino a 13 per soddisfare i costruttori di 2, 3 e 4.

Questa situazione diventa più difficile quando ho bisogno di 2, 3 o 4 per comportarmi in un certo modo in modo da poter testare la semplice decisione logica in # 1. Potrei aver bisogno di capire e "ragionare mentalmente" l'intero oggetto grafico / albero tutto in una volta per far sì che 2, 3 o 4 si comportino nel modo necessario. Spesso sembra molto più semplice eseguire myMockOfModule2.Setup (x => x.GoLeftOrRight ()). Returns (new Right ()); per testare che il modulo 1 risponde come previsto quando il modulo 2 gli dice di andare bene.

Se dovessi testare istanze concrete di 2 ... N ... 13 tutte insieme, le configurazioni del test sarebbero molto grandi e per lo più duplicate. Gli errori di test potrebbero non fare un ottimo lavoro nell'individuare le posizioni degli errori di regressione. I test non sarebbero indipendenti ( un altro link di supporto ).

Certo, è spesso ragionevole fare test basati sullo stato, piuttosto che sull'interazione, del livello inferiore, dal momento che quei moduli raramente hanno ulteriori dipendenze. Ma sembra che il deridere sia quasi necessario per definizione per isolare qualsiasi modulo al di sopra del fondo.

Alla luce di tutto ciò, qualcuno può dirmi cosa potrei perdere? Il nostro team sta abusando delle beffe? O c'è forse qualche ipotesi nella tipica guida ai test unitari secondo cui gli strati di dipendenza nella maggior parte delle applicazioni saranno abbastanza superficiali da poter ragionevolmente testare tutti i moduli di codice integrati insieme (rendendo il nostro caso "speciale")? O forse diversamente, il nostro team non delimita adeguatamente i nostri contesti limitati?


Mi sembra che la tua applicazione possa beneficiare di un accoppiamento più lento. en.wikipedia.org/wiki/Loose_coupling
Robert Harvey,

1
Or is there perhaps some assumption in typical unit testing guidance that the layers of dependency in most applications will be shallow enough that it is indeed reasonable to test all of the code modules integrated together (making our case "special")? <- Questo.
Robert Harvey,

Vale anche la pena notare: lo scopo dei test di regressione (in particolare i test di integrazione) è dimostrare che il software funziona ancora, non necessariamente identificare dove si interrompe. È possibile farlo con la risoluzione dei problemi, risolvere il problema e quindi coprire la rottura specifica con test unitari aggiuntivi.
Robert Harvey,

Avrei dovuto essere più chiaro nel post originale, per dire che il modulo 1 è a conoscenza solo di I2, I3 e I4. Il modulo 2 è a conoscenza solo di I5, I6 e I7. È solo l'obiettivo discutibile di testare senza usare beffe che fornirei 2, 3 e 4 a 1 concreti, portando alle sfide che ho descritto. Altrimenti, finiamo per usare le beffe molto più del 5% delle volte.
Ardave,

Ho scherzato sul fatto che il nostro caso fosse "speciale" dopo aver letto un post sul blog su molte squadre che sfidavano convenzioni preziose perché avevano erroneamente ritenuto che la loro situazione fosse "speciale". Ma se questo è effettivamente il nostro caso, ciò spiegherebbe la disparità tra alcune delle indicazioni della comunità che ho letto e alcune delle esperienze effettive del mio team. (il 5% contro il 70-90%)
ardave il

Risposte:


4

Il nostro team sta abusando delle beffe?

Non a prima vista.

Se hai 1..13 moduli, ognuno dovrebbe avere i propri test unitari e tutte le dipendenze (non banali, non attendibili) dovrebbero essere sostituite da versioni di test. Ciò può significare beffe, ma alcune persone sono pedanti nella denominazione, quindi falsi, spessori, oggetti nulli ... alcune persone si riferiscono a tutte le implementazioni di test come "derisioni". Questa potrebbe essere la fonte della confusione su quanto sia "giusto".

Personalmente, chiamo semplicemente tutti gli oggetti test "beffe" perché spesso non è utile distinguerli tra loro. Finché mantengono i miei test unitari veloci, isolati e resistenti ... Non mi interessa come si chiamano.


Mi chiedo allora se non v'è alcuna guida generale là fuori per quando è meglio per moduli di codice di prova in isolamento rispetto al test più di un modulo di codice, integrato insieme. Sembra che non appena integro due moduli che altrimenti avrei potuto isolare, mi apro a una serie di problemi indesiderati: mancanza di individuazione delle cause di regressione / test multipli falliti per una singola regressione, configurazioni di test eccessive, ecc. Ho il mio senso intuitivo ("ascolta i test") ma questo mi ha lasciato al livello di simulazione del 70-90%.
Ardave,

1
@nono - Nella mia esperienza, dovresti testare tutto da solo, per i motivi che dici. Le uniche cose che non testate unitamente in isolamento sono cose che non potete fare perché vanno direttamente contro un file system o altre risorse esterne ( qualcosa deve farlo dopo tutto).
Telastyn,

Dopo averlo masticato per alcuni giorni, la tua sembra la migliore spiegazione possibile: se si dovesse usare la definizione rigorosa di "derisione" come un tipo di doppio test usato per la verifica retrospettiva dell'interazione / comportamento, al contrario di un doppio test fittizio o un doppio di prova che è configurato in anticipo per simulare un certo comportamento, quindi sì, ho potuto vedere il completamento al livello del 5%.
Ardave,
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.