i miei anni di esperienza nello sviluppo di software suggeriscono che in pratica non può funzionare.
L'hai provato? Dave e io abbiamo scritto il libro sulla base di molti anni di esperienza collettiva, sia di noi stessi che di altre persone anziane in ThoughtWorks, facendo effettivamente le cose di cui discutiamo. Nulla nel libro è speculativo. Tutto ciò di cui discutiamo è stato provato e testato anche su grandi progetti distribuiti. Ma non ti suggeriamo di prenderlo per fede. Ovviamente dovresti provarlo tu stesso e scrivere ciò che trovi funziona e cosa no, incluso il contesto rilevante, in modo che gli altri possano imparare dalle tue esperienze.
La consegna continua si concentra principalmente sui test automatizzati. Spendiamo circa 1/3 del libro a parlarne. Lo facciamo perché l'alternativa, il test manuale, è costosa e soggetta a errori, e in realtà non è un ottimo modo per costruire software di alta qualità (come diceva Deming, "Smettere di dipendere dall'ispezione di massa per raggiungere la qualità. Migliorare il processo e costruire la qualità in il prodotto in primo luogo ")
La copertura completa del test è impossibile. Devi dedicare molto tempo - e il tempo è denaro - per ogni piccola cosa. Questo è prezioso, ma il tempo potrebbe essere speso per contribuire alla qualità in altri modi.
Naturalmente la copertura completa dei test è impossibile, ma qual è l'alternativa: copertura zero test? C'è un compromesso. Nel mezzo c'è la risposta corretta per il tuo progetto. Troviamo che in generale dovresti aspettarti di dedicare circa il 50% del tuo tempo alla creazione o alla manutenzione di test automatici. Ciò può sembrare costoso fino a quando non si considerano i costi di test manuali completi e di correzione dei bug che emergono dagli utenti.
Alcune cose sono difficili da testare automaticamente. Ad esempio la GUI. Anche il selenio non ti dirà se la tua GUI è traballante.
Ovviamente. Dai un'occhiata al quadrante di prova di Brian Marick. È ancora necessario eseguire manualmente test esplorativi e test di usabilità. Ma è per questo che dovresti usare i tuoi costosi e preziosi esseri umani, non i test di regressione. La chiave è che è necessario implementare una pipeline di distribuzione in modo da preoccuparsi solo di eseguire costose convalide manuali contro build che hanno superato una suite completa di test automatizzati. In questo modo riduci sia la quantità di denaro che spendi per i test manuali, sia il numero di bug che sono mai passati a test o produzione manuali (a quel punto sono molto costosi da risolvere). I test automatizzati eseguiti correttamente sono molto più economici nel ciclo di vita del prodotto, ma ovviamente si tratta di una spesa in conto capitale che si ammortizza nel tempo.
L'accesso al database è difficile da testare senza dispositivi ingombranti e anche questo non copre strani casi angolari nella memoria dei dati. Allo stesso modo la sicurezza e molte altre cose. Solo il codice di livello aziendale è effettivamente testabile in unità.
L'accesso al database viene testato implicitamente dai test di accettazione funzionale basati sullo scenario end-to-end. La sicurezza richiederà una combinazione di test automatici e manuali - test di penetrazione automatizzati e analisi statiche per trovare (ad esempio) sovraccarichi del buffer.
Anche nel livello aziendale, la maggior parte del codice non ha funzioni semplici i cui argomenti e valori di ritorno possono essere facilmente isolati a scopo di test. Puoi dedicare molto tempo alla costruzione di oggetti finti, che potrebbero non corrispondere alle implementazioni reali.
Ovviamente i test automatizzati sono costosi se si costruiscono male il software e i test. Consiglio vivamente di dare un'occhiata al libro "software orientato agli oggetti in crescita, guidato da test" per capire come farlo nel modo giusto affinché i test e il codice siano mantenibili nel tempo.
I test di integrazione / funzionali integrano i test unitari, ma richiedono molto tempo per essere eseguiti poiché di solito comportano la reinizializzazione dell'intero sistema su ciascun test. (Se non si reinizializza, l'ambiente di test è incoerente.)
Uno dei prodotti su cui lavoravo ha una serie di 3.500 test di accettazione end-to-end che richiedono 18 ore per l'esecuzione. Lo eseguiamo in parallelo su una griglia di 70 scatole e riceviamo feedback in 45m. Ancora più a lungo dell'ideale, ecco perché lo eseguiamo come seconda fase della pipeline dopo che i test unitari sono stati eseguiti in pochi minuti, quindi non sprechiamo le nostre risorse in un build che non ha un livello base di fiducia in.
Il refactoring o qualsiasi altra modifica interrompe molti test. Passi molto tempo a ripararli. Se si tratta di convalidare modifiche significative delle specifiche, va bene, ma spesso i test si interrompono a causa di dettagli di implementazione di basso livello senza significato, non cose che forniscono davvero informazioni importanti. Spesso la messa a punto è focalizzata sulla rielaborazione degli interni del test, non sul vero controllo della funzionalità che viene testata.
Se il codice e i test sono ben incapsulati e liberamente accoppiati, il refactoring non interromperà molti test. Descriviamo nel nostro libro come fare la stessa cosa anche per i test funzionali. Se i tuoi test di accettazione si interrompono, questo è un segno che stai perdendo uno o più test unitari, quindi parte del CD comporta un costante miglioramento della copertura dei test per cercare di trovare bug in precedenza nel processo di consegna in cui i test sono più accurati e il i bug sono più economici da correggere.
I rapporti sul campo relativi ai bug non possono essere facilmente abbinati alla precisa micro versione del codice.
Se stai testando e rilasciando più frequentemente (parte del punto del CD), è relativamente semplice identificare la modifica che ha causato il bug. L'intero punto del CD è ottimizzare il ciclo di feedback in modo da poter identificare i bug il prima possibile dopo che sono stati registrati per il controllo della versione - e in effetti, preferibilmente prima che vengano archiviati (motivo per cui eseguiamo i test di build e unità prima del check-in).