Come si esegue lo unit test di uno unit test? [chiuso]


89

Stavo guardando i webcast di Rob Connerys sull'app MVCStoreFront e ho notato che stava testando anche le cose più banali, cose come:

public Decimal DiscountPrice
{
   get
   {
       return this.Price - this.Discount;
   }
}

Avrebbe un test come:

[TestMethod]
public void Test_DiscountPrice
{
    Product p = new Product();
    p.Price = 100;
    p.Discount = 20;
    Assert.IsEqual(p.DiscountPrice,80);
}

Sebbene io sia tutto per i test di unità, a volte mi chiedo se questa forma di sviluppo del primo test sia davvero vantaggioso, ad esempio, in un processo reale, hai 3-4 livelli sopra il tuo codice (richiesta aziendale, documento dei requisiti, documento di architettura) , dove la regola di business definita effettiva (Prezzo scontato è Prezzo - Sconto) potrebbe essere definita in modo errato.

Se è così, il tuo unit test non significa nulla per te.

Inoltre, il tuo unit test è un altro punto di errore:

[TestMethod]
public void Test_DiscountPrice
{
    Product p = new Product();
    p.Price = 100;
    p.Discount = 20;
    Assert.IsEqual(p.DiscountPrice,90);
}

Ora il test è difettoso. Ovviamente in un semplice test, non è un grosso problema, ma diciamo che stavamo testando una regola aziendale complicata. Cosa ci guadagniamo qui?

Avanzamento rapido di due anni nella vita dell'applicazione, quando gli sviluppatori di manutenzione la mantengono. Ora l'azienda cambia la sua regola e il test si interrompe di nuovo, qualche sviluppatore alle prime armi risolve il test in modo errato ... ora abbiamo un altro punto di errore.

Tutto quello che vedo sono più possibili punti di errore, senza un reale ritorno vantaggioso, se il prezzo di sconto è sbagliato, il team di test troverà ancora il problema, come ha fatto il test unitario a salvare il lavoro?

Cosa mi manca qui? Per favore, insegnami ad amare il TDD, poiché finora ho difficoltà ad accettarlo come utile. Lo voglio anch'io, perché voglio rimanere progressista, ma non ha senso per me.

EDIT: un paio di persone continuano a dire che i test aiutano a far rispettare le specifiche. È stata la mia esperienza che anche le specifiche sono state sbagliate, il più delle volte, ma forse sono condannato a lavorare in un'organizzazione in cui le specifiche sono scritte da persone che non dovrebbero scrivere le specifiche.


5
in molti casi lo unit test è la specifica e anche la documentazione!
Steven A. Lowe,

32
... e poi unit test lo unit test dello unit test ... ma per quanto riguarda l'unità ^ 4 test e l'unità ^ 5 test ... aaaaaaaaahhhhhhhhh!
dacracot

14
Nessun tipo di test ti salverà da una specifica sbagliata.
Bill the Lizard

4
Qualcun altro ha appena sentito quello che sembrava il battito di una mano?
gnovice

9
Penso che la citazione appropriata sia "Sono solo tartarughe fino in fondo".
Quinn Taylor il

Risposte:


63

In primo luogo, il test è come la sicurezza: non si può mai essere sicuri al 100% di averlo ottenuto, ma ogni livello aggiunge più sicurezza e una struttura per risolvere più facilmente i problemi che rimangono.

In secondo luogo, è possibile suddividere i test in subroutine che a loro volta possono essere testati. Quando hai 20 test simili, creare una subroutine (testata) significa che il tuo test principale è di 20 semplici invocazioni della subroutine che è molto più probabile che sia corretta.

In terzo luogo, alcuni sostengono che TDD affronti questa preoccupazione. Cioè, se scrivi solo 20 test e passano, non sei completamente sicuro che stiano effettivamente testando qualcosa. Ma se ogni test che hai scritto inizialmente non è riuscito e poi l'hai risolto, sei molto più sicuro che stia davvero testando il tuo codice. IMHO questo avanti e indietro richiede più tempo di quanto ne valga la pena, ma è un processo che cerca di affrontare la tua preoccupazione.


2
Per giocare a devils advocate, vedo livelli aggiuntivi come più possibili punti di fallimento, il che non aumenta la fiducia per me. Nel mio vero lavoro, lavoro con molti team su un'azienda SOA altamente distribuita. Ciascuno di questi team potrebbe mettere a repentaglio il progetto se il loro livello fallisce.
FlySwat

2
Questo è il motivo per cui stai usando oggetti fittizi per testare ogni livello separatamente.
Toon Krijthe

10
Fantastico, quindi il mio test passerà usando IMockedComplexObject ma quando uso effettivamente un ComplexObject nel mondo reale, fallisce ... Non ho guadagnato nulla di nuovo.
FlySwat

16
@ Jonathan - no, hai acquisito la fiducia che il tuo codice funzioni - supponendo che tu abbia sviluppato l'interfaccia di ComplexObject e adeguatamente testato su tale interfaccia. Nel peggiore dei casi, hai acquisito la consapevolezza che la tua comprensione di ComplexObject non era quella che ti aspettavi.
tvanfosson

9
@FlySwat: in risposta al tuo commento su IMockedComplexObject, cito il commento di Cwash su un'altra risposta: "Non deridi quello che stai cercando di testare, prendi in giro quello che non stai cercando di testare."
Brian

39

È improbabile che un test errato interrompa il codice di produzione. Almeno, non peggio che non avere alcun test. Quindi non è un "punto di errore": i test non devono essere corretti affinché il prodotto funzioni effettivamente. Potrebbe essere necessario che siano corretti prima che venga confermato come funzionante, ma il processo di correzione di eventuali test non funzionanti non mette in pericolo il codice di implementazione.

Puoi pensare ai test, anche banali come questi, come una seconda opinione su ciò che il codice dovrebbe fare. Un'opinione è la prova, l'altra è l'attuazione. Se non sono d'accordo, allora sai di avere un problema e guardi più da vicino.

È anche utile se qualcuno in futuro desidera implementare la stessa interfaccia da zero. Non dovrebbero leggere la prima implementazione per sapere cosa significa Sconto, ei test fungono da supporto inequivocabile a qualsiasi descrizione scritta dell'interfaccia che potresti avere.

Detto questo, stai scambiando il tempo. Se ci sono altri test che potresti scrivere usando il tempo che risparmi saltando questi test banali, forse sarebbero più preziosi. Dipende dalla configurazione del test e dalla natura dell'applicazione, davvero. Se lo sconto è importante per l'app, rileverai comunque eventuali bug in questo metodo nei test funzionali. Tutto ciò che fa il test di unità è consentirti di catturarli nel punto in cui stai testando questa unità, quando la posizione dell'errore sarà immediatamente ovvia, invece di aspettare che l'app sia integrata insieme e la posizione dell'errore potrebbe essere meno ovvia.

A proposito, personalmente non userei 100 come prezzo nel test case (o meglio, se lo facessi, aggiungerei un altro test con un altro prezzo). Il motivo è che qualcuno in futuro potrebbe pensare che lo sconto dovrebbe essere una percentuale. Uno degli scopi di test banali come questo è garantire che gli errori nella lettura delle specifiche vengano corretti.

[Riguardo alla modifica: penso sia inevitabile che una specifica errata sia un punto di fallimento. Se non sai cosa dovrebbe fare l'app, è probabile che non lo farà. Ma scrivere test per riflettere le specifiche non ingrandisce questo problema, semplicemente non riesce a risolverlo. Quindi non stai aggiungendo nuovi punti di errore, stai solo rappresentando gli errori esistenti nel codice invece della documentazione waffle .]


4
Un test sbagliato lascerà il codice rotto in libertà. È qui che viene introdotto il fallimento. Fornisce un falso senso di fiducia.
FlySwat

9
È vero, ma non avere test consente anche di eliminare il codice rotto. L'errore è pensare che se il codice supera i test unitari deve essere corretto - ne sono stato guarito all'inizio della mia carriera. Quindi un test unitario non funzionante non consente al codice rotto di uscire allo stato brado, lo fa solo uscire nel test di integrazione.
Steve Jessop,

7
Inoltre, anche un test sbagliato può rilevare codice non funzionante, a condizione che contenga errori diversi dall'implementazione. Questo è il mio punto di vista che i test non devono assolutamente essere corretti, sono lì per attirare la tua attenzione sulle aree di interesse.
Steve Jessop,

2
risposta molto interessante.
Peter

22

Tutto quello che vedo sono più possibili punti di errore, senza un reale ritorno vantaggioso, se il prezzo di sconto è sbagliato, il team di test troverà ancora il problema, come ha fatto il test unitario a salvare il lavoro?

Il test unitario non dovrebbe davvero risparmiare lavoro, ma dovrebbe aiutarti a trovare e prevenire bug. È più lavoro, ma è il tipo giusto di lavoro. Si tratta di pensare al codice ai livelli più bassi di granularità e di scrivere casi di test che dimostrano che funziona nelle condizioni previste , per un dato insieme di input. Sta isolando le variabili in modo da poter risparmiare tempo cercando nel posto giusto quando si presenta un bug. Sta salvando quella suite di test in modo che tu possa usarli ancora e ancora quando devi apportare una modifica lungo la strada.

Personalmente penso che la maggior parte delle metodologie non siano molti passaggi rimossi dall'ingegneria del software del culto del carico , TDD incluso, ma non è necessario aderire al rigoroso TDD per raccogliere i vantaggi dei test unitari. Conserva le parti buone e butta via quelle che danno poco beneficio.

Infine, la risposta alla tua domanda principale " Come esegui il test unitario di un test unitario? " È che non dovresti. Ogni test unitario dovrebbe essere semplice come un morto cerebrale. Chiama un metodo con un input specifico e confrontalo con l'output previsto. Se la specifica per un metodo cambia, allora puoi aspettarti che anche alcuni degli unit test per quel metodo debbano cambiare. Questo è uno dei motivi per cui esegui gli unit test con un livello di granularità così basso, quindi solo alcuni degli unit test devono cambiare. Se si scopre che i test per molti metodi diversi stanno cambiando per una modifica in un requisito, è possibile che non si stia eseguendo il test con un livello di granularità sufficientemente preciso.


"Chiama un metodo con un input specifico e confrontalo con l'output previsto." ma cosa succede se l'output è un tipo complesso ... come un documento XML. Non puoi semplicemente "==", dovrai scrivere codice specifico per il confronto, e quindi forse il tuo metodo di confronto potrebbe essere difettoso ??
andy

@andy: devi testare il tuo metodo di confronto separatamente. Dopo averlo testato a fondo, puoi fare affidamento sul fatto che funzioni in altri test.
Bill the Lizard

bello, grazie Bill. Ho iniziato a lavorare in un posto nuovo ed è la mia prima volta con Unit Testing. Penso che in linea di principio funzioni, e stiamo usando il Cruise Control dove è davvero utile, ma grandi serie di test sembrano subire la stessa sorte del codice legacy ... Non ne sono sicuro ...
andy

11

I test unitari sono lì in modo che le tue unità (metodi) facciano ciò che ti aspetti. Scrivere prima il test ti costringe a pensare a cosa ti aspetti prima di scrivere il codice. Pensare prima di fare è sempre una buona idea.

I test unitari dovrebbero riflettere le regole aziendali. Certo, possono esserci errori nel codice, ma scrivere prima il test ti consente di scriverlo dal punto di vista della regola aziendale prima che il codice sia stato scritto. Scrivere il test in seguito, penso, è più probabile che porti all'errore che descrivi perché sai come il codice lo implementa e sei tentato solo di assicurarti che l'implementazione sia corretta, non che l'intento sia corretto.

Inoltre, gli unit test sono solo una forma - e la più bassa, in questo - di test che dovresti scrivere. Dovrebbero essere scritti anche test di integrazione e test di accettazione, questi ultimi dal cliente, se possibile, per assicurarsi che il sistema funzioni nel modo previsto. Se si riscontrano errori durante questo test, tornare indietro e scrivere unit test (che non riescono) per testare la modifica della funzionalità per farlo funzionare correttamente, quindi modificare il codice per superare il test. Ora hai test di regressione che catturano le tue correzioni di bug.

[MODIFICARE]

Un'altra cosa che ho scoperto facendo TDD. Impone quasi un buon design per impostazione predefinita. Questo perché i progetti altamente accoppiati sono quasi impossibili da testare singolarmente. Non ci vuole molto a usare TDD per capire che l'utilizzo di interfacce, inversione del controllo e inserimento di dipendenze, tutti modelli che miglioreranno la progettazione e ridurranno l'accoppiamento, sono davvero importanti per il codice testabile.


Forse è qui che sta il mio problema. Posso visualizzare l'algoritmo per una regola aziendale un po 'più facilmente di quanto possa visualizzare il risultato, quindi non ho problemi a implementare il codice stesso, ma ritengo ridondante la derisione della regola. Forse è proprio come penso.
FlySwat

Questo è esattamente quello che fai in uno unit test. Rompi l'algoritmo in pezzi e controlla ogni pezzo. In genere, trovo che il mio codice si scrive da solo perché ho già scritto l'aspettativa nel mio unit test.
tvanfosson

Mock è un termine sovraccarico nello spazio di test. Non deridi ciò che stai cercando di testare, prendi in giro ciò che non stai cercando di testare ... Quando scrivi il test per la tua regola aziendale, crei un codice che lo invoca, non lo deride affatto .
cwash

@cwash - Non sono sicuro di come il tuo commento si applichi alla mia risposta. Non ho parlato di beffa ... e sono d'accordo con la tua osservazione.
tvanfosson

@tvanfosson - il mio ultimo commento è stato in risposta a @FlySwat "... deridendo la regola come ridondante." Scusa ho dimenticato di specificare.
cwash

10

Come si verifica un test ? Il test di mutazione è una tecnica preziosa che ho usato personalmente con risultati sorprendentemente buoni. Leggi l'articolo collegato per maggiori dettagli e link a riferimenti ancora più accademici, ma in generale "testa i tuoi test" modificando il tuo codice sorgente (cambiando "x + = 1" in "x - = 1" per esempio) e poi rieseguire i test, assicurandosi che almeno un test abbia esito negativo. Eventuali mutazioni che non causano errori nei test vengono contrassegnate per un'indagine successiva.

Saresti sorpreso di come puoi avere una copertura di linee e rami del 100% con una serie di test che sembrano completi, eppure puoi cambiare fondamentalmente o persino commentare una riga nella tua fonte senza che nessuno dei test si lamenti. Spesso questo si riduce a non testare con gli input giusti per coprire tutti i casi limite, a volte è più sottile, ma in tutti i casi sono rimasto impressionato da quanto ne è uscito.


1
+1 concetto interessante di cui non avevo ancora sentito parlare
Wim Coenen

9

Quando si applica Test-Driven Development (TDD), si inizia con un test non riuscito . Questo passaggio, che potrebbe sembrare non necessario, in realtà è qui per verificare che lo unit test stia testando qualcosa. In effetti, se il test non fallisce mai, non porta alcun valore e peggio, porta a una fiducia sbagliata poiché ti affiderai a un risultato positivo che non sta dimostrando nulla.

Seguendo rigorosamente questo processo, tutte le '' unità '' sono protette dalla rete di sicurezza che gli unit test stanno facendo, anche le più banali.

Assert.IsEqual(p.DiscountPrice,90);

Non c'è motivo per cui il test si evolva in quella direzione o mi manca qualcosa nel tuo ragionamento. Quando il prezzo è 100 e lo sconto 20, il prezzo scontato è 80. Questo è come un invariante.

Ora immagina che il tuo software debba supportare un altro tipo di sconto basato sulla percentuale, forse a seconda del volume acquistato, il tuo metodo Product :: DiscountPrice () potrebbe diventare più complicato. Ed è possibile che l'introduzione di tali modifiche infranga la semplice regola di sconto che avevamo inizialmente. Quindi vedrai il valore di questo test che rileverà immediatamente la regressione.


Rosso - Verde - Refactoring - questo serve a ricordare l'essenza del processo TDD.

Il rosso si riferisce alla barra rossa di JUnit quando un test fallisce.

Il verde è il colore della barra di avanzamento di JUnit quando tutti i test vengono superati.

Refactoring in condizioni verdi: rimuovere qualsiasi dupliation, migliorare la leggibilità.


Ora, per affrontare il tuo punto sui "3-4 livelli sopra il codice", questo è vero in un processo tradizionale (simile a una cascata), non quando il processo di sviluppo è agile. E agile è il mondo da cui proviene il TDD; TDD è la pietra angolare della programmazione eXtreme .

Agile riguarda la comunicazione diretta piuttosto che i documenti sui requisiti gettati al muro.


8

Anche se sono tutto per i test unitari, a volte mi chiedo se questa forma di sviluppo del primo test sia davvero vantaggioso ...

Test piccoli e banali come questo possono essere il "canarino nella miniera di carbone" per la tua base di codice, avvisando del pericolo prima che sia troppo tardi. I test banali sono utili da tenere in giro perché ti aiutano a ottenere le giuste interazioni.

Ad esempio, pensa a un test banale messo in atto per sondare come utilizzare un'API con cui non hai familiarità. Se quel test ha qualche rilevanza per ciò che stai facendo nel codice che utilizza l'API "per davvero", è utile mantenere quel test in giro. Quando l'API rilascia una nuova versione ed è necessario eseguire l'aggiornamento. Ora hai le tue ipotesi su come ti aspetti che l'API si comporterà registrate in un formato eseguibile che puoi utilizzare per catturare le regressioni.

... [I] n un processo reale, hai 3-4 livelli sopra il tuo codice (richiesta commerciale, documento dei requisiti, documento dell'architettura), dove la regola di business definita effettiva (prezzo scontato è prezzo - sconto) potrebbe essere definita in modo errato. Se è così, il tuo unit test non significa nulla per te.

Se codifichi da anni senza scrivere test, potrebbe non essere immediatamente ovvio che ci sia un valore. Ma se sei dell'idea che il modo migliore per lavorare sia "rilascia presto, rilascia spesso" o "agile" in quanto desideri la capacità di implementare rapidamente / continuamente, allora il tuo test significa sicuramente qualcosa. L'unico modo per farlo è legittimare ogni modifica apportata al codice con un test. Non importa quanto piccolo sia il test, una volta che hai una suite di test verde, sei teoricamente OK da distribuire. Vedi anche "produzione continua" e "beta perpetua".

Non devi nemmeno essere "testato prima" per essere di questa mentalità, ma questo è generalmente il modo più efficiente per arrivarci. Quando esegui TDD, ti blocchi in un piccolo ciclo di Red Green Refactor da due a tre minuti. In nessun momento non sei in grado di fermarti e andartene e avere un pasticcio completo tra le mani che impiegherà un'ora per eseguire il debug e rimontare.

Inoltre, il tuo unit test è un altro punto di errore ...

Un test di successo è quello che dimostra un errore nel sistema. Un test fallito ti avviserà di un errore nella logica del test o nella logica del tuo sistema. L'obiettivo dei test è rompere il codice o dimostrare che uno scenario funziona.

Se stai scrivendo test dopo il codice, corri il rischio di scrivere un test che è "cattivo" perché per vedere che il tuo test funziona davvero, devi vederlo sia rotto che funzionante. Quando scrivi dei test dopo il codice, questo significa che devi "far scattare la trappola" e introdurre un bug nel codice per vedere il test fallire. La maggior parte degli sviluppatori non solo è a disagio per questo, ma sosterrebbe che è una perdita di tempo.

Cosa ci guadagniamo qui?

C'è sicuramente un vantaggio nel fare le cose in questo modo. Michael Feathers definisce "codice legacy" come "codice non testato". Quando si adotta questo approccio, si legittima ogni modifica apportata alla propria base di codice. È più rigoroso che non usare i test, ma quando si tratta di mantenere una grande base di codice, si ripaga da solo.

A proposito di piume, ci sono due ottime risorse che dovresti controllare in merito a questo:

Entrambi spiegano come trasformare questi tipi di pratiche e discipline in progetti che non sono "Greenfield". Forniscono tecniche per scrivere test su componenti strettamente accoppiati, dipendenze cablate e cose su cui non si ha necessariamente il controllo. Si tratta di trovare "giunzioni" e testarle intorno.

[I] Se il prezzo scontato è sbagliato, il team di test troverà comunque il problema, come ha fatto il test unitario a risparmiare lavoro?

Abitudini come queste sono come un investimento. I resi non sono immediati; si accumulano nel tempo. L'alternativa al non test è essenzialmente assumersi il debito di non essere in grado di catturare regressioni, introdurre codice senza timore di errori di integrazione o guidare le decisioni di progettazione. Il bello è che legittimi ogni cambiamento introdotto nella tua base di codice.

Cosa mi manca qui? Per favore, insegnami ad amare il TDD, poiché finora ho difficoltà ad accettarlo come utile. Lo voglio anch'io, perché voglio rimanere progressista, ma per me non ha senso.

La considero una responsabilità professionale. È un ideale verso cui tendere. Ma è molto difficile da seguire e noioso. Se ti interessa e ritieni di non dover produrre codice non testato, sarai in grado di trovare la forza di volontà per apprendere buone abitudini di test. Una cosa che faccio molto ora (come fanno gli altri) è timebox io stesso un'ora per scrivere codice senza alcun test, quindi avere la disciplina per buttarlo via. Può sembrare uno spreco, ma non lo è davvero. Non è che l'esercizio costa a un'azienda materiali fisici. Mi ha aiutato a capire il problema e come scrivere codice in modo tale che sia di qualità superiore e testabile.

Il mio consiglio alla fine sarebbe che se davvero non hai il desiderio di essere bravo, allora non farlo affatto. Test scadenti che non vengono mantenuti, non funzionano bene, ecc. Possono essere peggio che non avere alcun test. È difficile imparare da soli e probabilmente non lo amerai, ma sarà quasi impossibile da imparare se non hai il desiderio di farlo o non riesci a vedere abbastanza valore in esso per garantire l'investimento di tempo.

Un paio di persone continuano a dire che i test aiutano a far rispettare le specifiche. È stata la mia esperienza che anche le specifiche sono state sbagliate, il più delle volte ...

La tastiera di uno sviluppatore è dove la gomma incontra la strada. Se la specifica è sbagliata e non alzi la bandiera, è molto probabile che tu venga incolpato per questo. O almeno lo farà il tuo codice. La disciplina e il rigore coinvolti nei test sono difficili da rispettare. Non è affatto facile. Ci vuole pratica, molto apprendimento e molti errori. Ma alla fine ripaga. In un progetto frenetico e in rapida evoluzione, è l'unico modo per dormire la notte, non importa se ti rallenta.

Un'altra cosa a cui pensare qui è che le tecniche che sono fondamentalmente le stesse dei test hanno dimostrato di funzionare in passato: "clean room" e "design by contract" tendono entrambi a produrre gli stessi tipi di costrutti "meta" -code che i test lo fanno e li impongono in punti diversi. Nessuna di queste tecniche è una pallottola d'argento e il rigore ti costerà alla fine in termini di funzionalità che puoi fornire in termini di time to market. Ma non è di questo che si tratta. Si tratta di essere in grado di mantenere ciò che offri. E questo è molto importante per la maggior parte dei progetti.


7

Il test unitario funziona in modo molto simile alla contabilità a partita doppia. Dichiarate la stessa cosa (regola aziendale) in due modi abbastanza diversi (come regole programmate nel vostro codice di produzione e come semplici esempi rappresentativi nei vostri test). È molto improbabile che tu commetta lo stesso errore in entrambi, quindi se entrambi sono d'accordo l'uno con l'altro, è piuttosto improbabile che tu abbia sbagliato.

In che modo il test varrà lo sforzo? Nella mia esperienza in almeno quattro modi, almeno durante lo sviluppo test driven:

  • ti aiuta a trovare un design ben disaccoppiato. È possibile solo codice di unit test ben disaccoppiato;
  • ti aiuta a determinare quando hai finito. Dover specificare il comportamento necessario nei test aiuta a non creare funzionalità che non sono effettivamente necessarie ea determinare quando la funzionalità è completa;
  • ti offre una rete di sicurezza per il refactoring, che rende il codice molto più suscettibile di modifiche; e
  • ti fa risparmiare un sacco di tempo per il debug, il che è terribilmente costoso (ho sentito stime che tradizionalmente gli sviluppatori trascorrono fino all'80% del loro tempo nel debug).

5

La maggior parte dei test unitari, ipotesi di test. In questo caso, il prezzo di sconto dovrebbe essere il prezzo meno lo sconto. Se le tue ipotesi sono sbagliate, scommetto che anche il tuo codice è sbagliato. E se commetti uno stupido errore, il test fallirà e lo correggerai.

Se le regole cambiano, il test fallirà e questa è una buona cosa. Quindi devi cambiare il test anche in questo caso.

Come regola generale, se un test fallisce subito (e non usi il test first design), o il test o il codice sono sbagliati (o entrambi se hai una brutta giornata). Usi il buon senso (e possibilmente le specifiche) per correggere il codice offensivo e rieseguire il test.

Come ha detto Jason, il test è sicurezza. E sì, a volte introducono lavoro extra a causa di test difettosi. Ma il più delle volte fanno risparmiare molto tempo. (E hai l'opportunità perfetta per punire il ragazzo che rompe il test (stiamo parlando di pollo di gomma)).


4

Prova tutto quello che puoi. Anche errori banali, come dimenticare di convertire i metri in piedi, possono avere effetti collaterali molto costosi. Scrivi un test, scrivi il codice da controllare, fallo passare, vai avanti. Chissà che in futuro qualcuno potrebbe cambiare il codice sconto. Un test può rilevare il problema.


Questo non risolve nessuno dei miei pensieri. Capisco il mantra di base del TDD ... Non vedo il vantaggio.
FlySwat

4

Vedo unit test e codice di produzione come aventi una relazione simbiotica. In poche parole: uno mette alla prova l'altro. Ed entrambi testano lo sviluppatore.


3

Ricorda che il costo della riparazione dei difetti aumenta (in modo esponenziale) man mano che i difetti vivono durante il ciclo di sviluppo. Sì, il team di test potrebbe rilevare il difetto, ma (di solito) occorrerà più lavoro per isolare e correggere il difetto da quel punto rispetto a se uno unit test non fosse riuscito, e sarà più facile introdurre altri difetti durante la riparazione se tu non hanno unit test da eseguire.

Di solito è più facile da vedere con qualcosa di più di un esempio banale ... e con esempi banali, beh, se in qualche modo sbagli lo unit test, la persona che lo rivede rileverà l'errore nel test o l'errore nel codice, oppure tutti e due. (Sono in fase di revisione, giusto?) Come sottolinea tvanfosson , i test unitari sono solo una parte di un piano SQA.

In un certo senso, gli unit test sono assicurativi. Non sono una garanzia che rileverai ogni difetto e, a volte, potrebbe sembrare che tu stia spendendo molte risorse per loro, ma quando rilevano difetti che puoi riparare, spenderai molto meno che se non avessi avuto alcun test e avessi dovuto correggere tutti i difetti a valle.


3

Capisco il tuo punto, ma è chiaramente sopravvalutato.

Il tuo argomento è fondamentalmente: i test introducono il fallimento. Pertanto i test sono cattivi / perdita di tempo.

Sebbene ciò possa essere vero in alcuni casi, non è certo la maggioranza.

TDD presuppone: più test = meno errori.

È più probabile che i test catturino i punti di fallimento piuttosto che introdurli.


1

Ancora più automazione può aiutare qui! Sì, scrivere unit test può richiedere molto lavoro, quindi utilizza alcuni strumenti per aiutarti. Dai un'occhiata a qualcosa come Pex, di Microsoft, se stai usando .Net Creerà automaticamente suite di unit test esaminando il tuo codice. Verrà presentato con test che forniscono una buona copertura, cercando di coprire tutti i percorsi attraverso il codice.

Naturalmente, solo guardando il tuo codice non può sapere cosa stavi effettivamente cercando di fare, quindi non sa se è corretto o meno. Ma genererà casi di test interessanti per te, quindi potrai esaminarli e vedere se si comporta come ti aspetti.

Se poi vai oltre e scrivi unit test parametrizzati (puoi pensarli come contratti, davvero), genererà casi di test specifici da questi, e questa volta può sapere se qualcosa non va, perché le tue asserzioni nei tuoi test falliranno.


1

Ho pensato un po 'a un buon modo per rispondere a questa domanda e vorrei tracciare un parallelo con il metodo scientifico. IMO, potresti riformulare questa domanda: "Come fai a sperimentare un esperimento?"

Gli esperimenti verificano le ipotesi empiriche (ipotesi) sull'universo fisico. I test unitari testeranno le ipotesi sullo stato o sul comportamento del codice che chiamano. Possiamo parlare della validità di un esperimento, ma è perché sappiamo, attraverso numerosi altri esperimenti, che qualcosa non va bene. Non ha né validità convergenteevidenza empirica . Non progettiamo un nuovo esperimento per testare o verificare la validità di un esperimento , ma possiamo progettare un esperimento completamente nuovo .

Quindi, come gli esperimenti , non descriviamo la validità di uno unit test in base al fatto che superi o meno uno unit test stesso. Insieme ad altri test unitari, descrive le ipotesi che facciamo sul sistema che sta testando. Inoltre, come gli esperimenti, cerchiamo di rimuovere quanta più complessità possibile da ciò che stiamo testando. "Il più semplice possibile, ma non più semplice."

A differenza degli esperimenti , abbiamo un asso nella manica per verificare che i nostri test siano validi oltre alla semplice validità convergente. Possiamo introdurre abilmente un bug che sappiamo dovrebbe essere catturato dal test e vedere se il test fallisce davvero. (Se solo potessimo farlo nel mondo reale, dipenderemmo molto meno da questa cosa della validità convergente!) Un modo più efficiente per farlo è guardare il tuo test fallire prima di implementarlo (il passaggio rosso in Red, Green, Refactor ).


1

È necessario utilizzare il paradigma corretto durante la scrittura dei test.

  1. Inizia scrivendo prima i tuoi test.
  2. Assicurati che non riescano a iniziare con.
  3. Falli passare.
  4. Revisione del codice prima di archiviare il codice (assicurati che i test vengano esaminati).

Non puoi essere sempre sicuro, ma migliorano i test complessivi.


0

Anche se non provi il tuo codice, sarà sicuramente testato in produzione dai tuoi utenti. Gli utenti sono molto creativi nel provare a mandare in crash il tuo software e trovare anche errori non critici.

La risoluzione dei bug in produzione è molto più costosa della risoluzione dei problemi nella fase di sviluppo. Come effetto collaterale, perderai entrate a causa di un esodo di clienti. Puoi contare su 11 clienti persi o non acquisiti per 1 cliente arrabbiato.

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.