Perché i test automatici continuano a fallire nella mia azienda?


178

Abbiamo provato più volte a introdurre test automatici per sviluppatori nella mia azienda. Il nostro team di controllo qualità utilizza Selenium per automatizzare i test dell'interfaccia utente, ma ho sempre voluto introdurre test unitari e test di integrazione. In passato, ogni volta che lo provavamo, tutti si eccitavano per il primo o due mesi. Poi, diversi mesi dopo, la gente semplicemente smette di farlo.

Alcune osservazioni e domande:

  1. I test automatici funzionano davvero? La maggior parte dei miei colleghi che lavoravano in altre aziende hanno tentato e fallito nell'attuare una strategia di test automatizzata. Non ho ancora visto una società di software di vita reale che la utilizza effettivamente e non ne parla solo. Quindi molti sviluppatori vedono i test automatizzati come qualcosa di eccezionale in teoria ma che non funziona nella realtà. Il nostro team aziendale vorrebbe che gli sviluppatori lo facessero anche con un costo del 30% in più (almeno lo dicono). Ma gli sviluppatori sono scettici.

  2. Nessuno sa davvero come eseguire correttamente i test automatizzati. Sì, abbiamo letto tutti gli esempi di test di unità su Internet, ma usarli per un grande progetto è qualcos'altro. Il principale colpevole è prendere in giro / stub il database o qualsiasi altra cosa non banale. Finisci per passare più tempo a deridere che a scrivere test reali. Quindi quando inizia a impiegare più tempo a scrivere test rispetto al codice, è allora che ti arrendi.

  3. Esistono buoni esempi di unit test / test di integrazione del sistema utilizzati in applicazioni web complesse incentrate sui dati? Qualche progetto open source? La nostra applicazione è incentrata sui dati ma ha anche molta logica di dominio. Ho provato l'approccio al repository a un certo punto e l'ho trovato abbastanza buono per i test unitari, ma è arrivato al prezzo di essere in grado di ottimizzare facilmente l'accesso ai dati e ha aggiunto un altro livello di complessità.

Abbiamo un grande progetto intrapreso da 20 sviluppatori esperti. Questo sembrerebbe un ambiente ideale per introdurre test unitari / test di integrazione.

Perché non funziona per noi? Come l'hai fatto funzionare nella tua azienda?


14
Qual è il tuo stack tecnologico?
Florian Margaine,

7
I moduli Web sono quasi impossibili da testare correttamente. È possibile utilizzare un modello MVP (Modello / Visualizza / Presentatore) per spostare la logica di presentazione in un componente testabile.
Pete,

12
@MasonWheeler: In entrambi i casi, hai costruito un argomento formidabile che smentisce premesse che non sono state accettate in primo luogo: cioè che i test unitari esistono per dimostrare la correttezza.
Steven Evers,

10
@ MasonWheeler- Usando quell'argomento non dovresti mai tentare alcun QA, perché non dimostrerai mai che non ci sono bug. Questo non è nemmeno l'obiettivo. Una buona interfaccia utente automatizzata e una strategia di test unitari sono solo per liberare il QA dai test tecnici e consentire loro di concentrarsi sui test esplorativi.
Alex

15
Sono scioccato dal fatto che diverse persone abbiano dichiarato di non aver mai visto i test automatici per più di qualche mese. Ho lavorato per circa cinque grandi aziende tedesche come consulente e ti licenzierebbero se non scrivessi dei test. Il test automatizzato non è un argomento teorico, è praticato con successo in tutto il mondo e aumenta significativamente la qualità del codice (se eseguito correttamente).

Risposte:


89

La parte più difficile del test unitario è ottenere la disciplina per scrivere i test prima / all'inizio. La maggior parte degli sviluppatori è abituata a immergersi semplicemente nel codice. Inoltre, rallenta presto il processo di sviluppo mentre stai cercando di capire come scrivere un test per il codice. Tuttavia, man mano che migliori i test, questo accelera. E a causa dei test di scrittura, la qualità iniziale del codice inizia più in alto.

All'inizio, prova solo a scrivere dei test. Non preoccuparti così tanto di prendere in giro / stubare le cose all'inizio. Mantieni i test semplici. I test sono codici e possono / devono essere sottoposti a refactoring. Anche se lungo quella linea se qualcosa è difficile da testare, potrebbe anche essere il design. TDD guida all'utilizzo della maggior parte dei modelli di progettazione (nella mia esperienza, in particolare il modello Factory).

Assicurarsi che i test ottengano un livello di visibilità. Integrali nel processo di rilascio, durante la revisione del codice chiedi di loro. Tutti i bug trovati dovrebbero essere sottoposti a un test. Queste cose sono dove brilla TDD.

Ecco un paio di risorse che ho trovato utili:

http://misko.hevery.com/attachments/Guide-Writing%20Testable%20Code.pdf

http://www.agitar.com/downloads/TheWayOfTestivus.pdf

Modificare:

Una cosa da tenere a mente quando si scrivono test. Non stai cercando di specificare nulla sull'implementazione del codice, ma solo sul comportamento. Quando scrivi il codice, lo provi continuamente. Prova di eseguirlo con istruzioni di debug e così via. Scrivere test lo formalizza e fornisce una registrazione dei test che hai. In questo modo puoi verificare la tua funzionalità con sicurezza senza saltare accidentalmente un caso di test che hai ricordato a metà del processo di sviluppo.


Un altro modo per avvicinarsi all'introduzione di questo come una funzione diagnostica ... noto anche come power on self test (POST) che può quasi spedire il codice cliente ... e non solo un mucchio di semplici test, che è ciò che test e funzioni dovrebbero essere.
Giustino

Inoltre, evitare TDD Anti-Patterns .
Gary Rowe,

4
Misko Hevery ha anche dei fantastici video su YouTube su come scrivere codice testabile che ho trovato prezioso. youtube.com/watch?v=acjvKJiOvXw
Despertar

"Assicurati che i test ottengano un livello di visibilità" - questo è fondamentale per il successo. Se nessuno può vedere come stanno andando i tuoi test, non vedranno il valore. I test dovrebbero essere eseguiti al check-in automaticamente come parte di un'integrazione continua e quindi riportati. Lavoro a Tesults ( tesults.com ) e il motivo per cui esiste è a causa dell'enorme visibilità offerta dai test di impatto.
Abilità M2

77

In molti modi sono d'accordo con la tua squadra.

  1. La maggior parte dei test unitari sono discutibili in termini di valore. Poiché la stragrande maggioranza dei test sembra essere troppo semplice.

  2. È molto più difficile scrivere un buon codice testabile rispetto al solo codice funzionante. C'è una grande percentuale della comunità di sviluppatori che crede nel farlo funzionare, rispetto alla qualità del codice / design in sé. E una percentuale ancora maggiore che non sa nemmeno cos'è il codice di qualità.

  3. La scrittura del codice unit test può richiedere molto più tempo del codice stesso.

  4. Capire come testare adeguatamente il codice più complicato (ad es. Le cose a cui sei veramente interessato a testare a fondo) va oltre le capacità di molti sviluppatori.

  5. Il mantenimento dei test unitari richiede troppo tempo. Piccoli cambiamenti possono avere grandi effetti a catena. L'obiettivo principale dei test di unità automatizzati è scoprire se le modifiche hanno violato il codice. Tuttavia, il 99% delle volte ciò che finisce per rompersi sono i test e non il codice.

Con tutti i problemi di cui sopra, non c'è ancora un modo migliore per essere in grado di apportare modifiche al codice e avere un certo livello di sicurezza che qualcosa non si è rotto inaspettatamente rispetto all'automazione dei test.

Alcuni di questi aspetti possono essere alleviati in una certa misura non seguendo il manuale del test unitario.

Molti tipi di progetti / applicazioni vengono testati meglio automatizzando i test a livello di modulo / pacchetto. Nella mia esperienza, la maggior parte degli errori di codifica non è dovuta al fatto che il codice in una classe è stato codificato in modo errato, ma perché il programmatore non ha capito come la loro classe avrebbe dovuto funzionare con altre classi. Ho visto un sacco di soldi per questo tipo di test. Ma ancora una volta, questi test sono più difficili da scrivere rispetto ai test unitari (a livello di classe).

Si riduce davvero al fatto che gli sviluppatori credano nel processo o meno. Se lo fanno, allora scriveranno buoni test unitari, troveranno errori in anticipo e saranno sostenitori. In caso contrario, i loro test unitari saranno in gran parte inutili e non troveranno alcun errore e la loro teoria dei test unitari inutili sarà dimostrata vera (nelle loro menti).

In conclusione, non ho mai visto l'approccio di test di unità automatizzato in piena regola funzionare per più di un paio di mesi, ma l'idea di test di unità automatizzati persiste anche se siamo selettivi in ​​ciò che ha davvero bisogno di test. Questo approccio tende ad avere molte meno critiche ed è più accettato da tutti gli sviluppatori piuttosto che da pochi.


24
Tendo ad essere d'accordo con questo .. Abbiamo preso l'abitudine di fare dei test solo dopo che qualcosa si è interrotto (anche se quella rottura era durante lo sviluppo). Mai in anticipo, richiede troppo tempo per una ricompensa troppo ridotta.
Izkata,

5
@Izkata l'altro approccio che ho visto fatto con successo è scrivere un numero relativamente piccolo di test di alto livello chiamando il Frobinate()metodo di livello superiore (invece delle dozzine di metodi più piccoli chiamati sotto di esso) dopo che il sistema è stato verificato con altri mezzi per servire come prova del fumo che nessuno dei cambiamenti di livello inferiore ha rotto nulla. In genere questi test utilizzavano gli stessi dati che facevano parte della sterlina nei test utente della tastiera forniti in modo che il cliente potesse vedere che il sistema stava facendo quello che voleva. Successivamente gli strumenti di copertura del codice possono identificare dove i casi limite non sono ancora coperti.
Dan Neely,

3
Non ho detto "test automatizzati completi", ho detto "test UNIT automatizzati completi". Grande differenza. Ho usato i test automatici a livello di modulo per almeno un decennio. Il test unitario è a livello di classe. Credo di avere più soldi per i soldi quando collaudo classi che dovrebbero lavorare insieme, piuttosto che come individui. Tuttavia, anche lì, utilizziamo ancora un approccio pragmatico e scegliamo selettivamente cosa / dove scrivere test automatizzati.
Dunk

2
Senza una buona copertura dei test unitari, come si effettua il refactoring? O senza refactoring, come si evita che il codice degeneri gradualmente in non mantenibilità?
Kevin Cline

1
@Leonardo Non l'hanno fatto - erano troppo spaventati per cambiare qualcosa. Oppure hanno risparmiato tutto quel debito tecnico e messo da parte qualche settimana / mese dopo per risolverlo in un unico grumo.
GraemeF

33

Il principale colpevole è beffardo / stub del database o qualsiasi cosa non semplice.

E c'è il tuo problema.

Tutti sottolineano bene come integrare i test unitari nel proprio ambiente. Come forzare le persone a farlo abbastanza da vedere il valore pratico e "si attacca". Ma se è molto doloroso da fare e / o non fornisce alcun vantaggio, non si attaccherà.

Staccare un database dovrebbe essere semplicissimo. Invece della tua interfaccia che va su un backup DB per fornire i suoi risultati, inserisci un semplice oggetto hardcoded. Se non riesci a farlo, il tuo design / architettura ha dei problemi. Il tuo codice presuppone che stia andando a un database o non hai l'astrazione dell'interfaccia per variare.

Questo non è semplicemente un problema di test / qualità. Non appena si desidera modificare i provider di database o passare al cloud o supportare app mobili non connesse, la progettazione non riesce. Se non puoi supportare i casi di flessibilità più semplici, non puoi certamente supportare le cose più complesse che la tua azienda richiederà inevitabilmente.


4
I valori di ritorno del database con codifica rigida da un piccolo stub di un oggetto simulato sono un buon modo per isolare il test da qualsiasi cosa nel database che potrebbe cambiare e rompere il codice (ad esempio, rinominare le colonne). È appropriato in determinate circostanze, ma è importante mantenere un database di test temporanei di facile utilizzo a meno che non si desideri che le cose si rompano un giorno quando lo si cambia. Se il codice si interrompe quando si scambia il database, questo è un errore del codice che il test dovrebbe catturare (e se si desidera evitarlo, si consiglia di eseguire la suite di test in più database.)

8
@fennec - i test unitari non sono lì per testare il database, sono lì per testare il codice che dipende dai valori del database per funzionare.
Telastyn,

3
Tutto bene fino a quando non state testando l'unità il codice che manipola il database. : P che, per molte persone, è molto del loro codice.

4
@fennec - È leggermente più complesso di un semplice dead stub dell'interfaccia per assicurarsi che le tue scritture scrivano l'oggetto giusto. Diventa difficile solo quando le tue classi stanno cercando di inviare SQL direttamente nell'interfaccia (leggi: hai un design orribile).
Telastyn,

5
@Telastyn forse sto fraintendendo, ma alla fine qualche classe ha bisogno di andare giù e sporcare e scrivere l'SQL o scrivere il file o inviare i dati o l'interfaccia con la GPU. La maggior parte delle astrazioni ha inevitabili perdite a un certo livello; sono semplicemente pragmatici e non necessariamente orribili.
Coda degli apprendisti

21

Devi iniziare con qualcosa di piccolo, semplice da automatizzare e di alto valore. Abbassa un po 'di frutta dolce e bassa e sarai in grado di vendere il processo. Mostra come ha salvato qualcuno a tarda notte o durante un fine settimana. Quindi puoi espanderti da lì.

Per eseguire correttamente i test automatizzati, hai bisogno di qualcuno che sia una risorsa e un evangelista e che abbia acquisito da gestioni di livello superiore.

Tratta il tuo sviluppo di test automatizzato come qualsiasi altro progetto agile. Produrre test completati su base regolare.

Aggiunta da un commento: questo è più un problema di gestione. Il codice è considerato "fatto" prima di essere documentato? Prima che sia registrato? Prima che includa e superi i test unitari?

Il modo in cui approcci questo dipende davvero dal tuo ruolo. Sei un pari? In tal caso, mostra agli altri come è più facile riutilizzare e gestire il tuo codice. Sei un protagonista? Scegli il tuo programmatore che ha il maggior numero di problemi con il codice e aiutali ad aggiungere test per evitare tali problemi. Sei un capo? Impostalo come standard che "il codice non viene eseguito fino a quando i test unitari non vengono inseriti e superati.


17
"Abbatti un po 'di frutta dolce e bassa e sarai in grado di vendere il processo.": Penso che siano già arrivati ​​a questa fase (hanno visto potenziali vantaggi nell'uso dei test unitari) ed è per questo che sono stati convinti di dargli un tentativo. Il problema è piuttosto come ridimensionare i frutti a bassa pendenza per fare sistematicamente test unitari. L'unico progetto a cui ho lavorato in cui i test unitari venivano sistematicamente utilizzati aveva un codice di test unitario maggiore rispetto al codice prodotto effettivo. Se un team non è disposto a dedicare più tempo alla codifica di unit test rispetto all'effettivo codice dell'applicazione, allora l'approccio IMO probabilmente non funzionerà.
Giorgio,

4
Questo è più un problema di gestione. Il codice è considerato "fatto" prima di essere documentato? Prima che sia registrato? Prima che includa e superi i test unitari? Il modo in cui approcci questo dipende davvero dal tuo ruolo. Sei un pari? In tal caso, mostra agli altri come è più facile riutilizzare e gestire il tuo codice. Sei un protagonista? Scegli il tuo programmatore che ha il maggior numero di problemi con il codice e aiutali ad aggiungere test per evitare tali problemi. Sei un capo? Imposta come standard che "il codice non viene eseguito fino a quando i test unitari non sono in corso e superano.
Salta Huffman

1
@SkipHuffman il tuo commento dovrebbe essere aggiunto come modifica alla risposta corrente.
Radu Florescu,

15

Segui queste regole di base. test:

  1. deve funzionare regolarmente! Puoi eseguire i test su ogni build, prima / dopo ogni check-in o solo ogni mattina. L'attivazione automatica è altamente preferibile all'attivazione manuale. Perché mentre in teoria puoi far sì che tutti i membri del team siano responsabili di garantire che eseguano i test, se non è automatizzato, probabilmente non sta accadendo abbastanza spesso! E se non esegui i test abbastanza spesso, entrambi trovano i bug troppo tardi incoraggiando molti test interrotti, il che porta al punto 2:

  2. Avrai comunque successo solo se quei test, ora eseguiti regolarmente, non si frappongono . Con questo intendiamo test:

    un. non deve impiegare troppo tempo a correre (soggettivamente) per il valore che forniscono! Rendi i tuoi test velocissimi. Non lasciare che le persone effettuino il check-in dei test che saranno una perdita di tempo per farli correre!

    b. non deve essere inaffidabile. Evitare per quanto possibile test multithread. Applica le pratiche di ingegneria ai tuoi test proprio come il tuo altro codice: in particolare - ripassa i test sui codici!

    c. non deve essere più difficile da correggere e mantenere rispetto al codice effettivo testato. La tua velocità di codifica farà davvero schifo se una minuscola modifica di una riga al tuo codebase richiede di correggere 10 test diversi.

Infine, la regola numero 3. I test non devono non solo fornire un valore negativo, come nella regola 2, ma devono fornire un valore positivo. Test ...

  1. in realtà ti sta dicendo qualcosa a cui tieni quando falliscono! (Nessun test con oscuri messaggi di errore, o semplicemente per darti reclami ridicoli come "hai dimenticato di eseguire il test su un computer Windows 2008", per favore!).

Un modo popolare per violare la regola 3 è testare la cosa sbagliata . Questo a volte perché un test è troppo grande o troppo sfocato. Ma di solito deriva dal non testare qualcosa di cui un cliente si preoccuperà e dal test di dettagli di implementazione irrilevanti. (Ma a volte testare i dettagli dell'implementazione rende anche un test efficiente: l'IMO richiede solo pratica per decidere quale.)

Conclusione: queste regole di base indicano la direzione generale di una disciplina di sperimentazione sostenibile , che è ciò che desideri disperatamente. Durante il test, chiediti se questo test è realmente sostenibile e mantenibile. Ricorda:

  • se i test non sono sostenibili, cadono in disuso e quindi diventano sprechi
  • se i test non sono sostenibili, smetti di fare test e il tuo team smette di migliorare nei test! E, ultimo punto:

Il test è in realtà difficile. Dovresti aspettarti che i test del tuo team faranno sostanzialmente schifo quando inizi a scrivere test . Non scoraggiarti. Non buttare via i vecchi test, ogni volta che si nota fanno schifo e sono insostenibili.


12

1. Funziona davvero?

Sì, se fatto correttamente. Il punto è che i tester devono regolare ed estendere i loro script automatici dopo che gli ingegneri hanno implementato nuove funzionalità.

2. Nessuno ha veramente esperienza o sa come eseguire correttamente i test automatizzati.

Ottieni un consulente (qualcuno che sappia come è fatto correttamente). Oppure, investi più tempo. L'alternativa è quella di avere un team di test più grande, che esegue manualmente lo stesso test (che è soggetto a errori).

3.Abbiamo un grande progetto con 20 sviluppatori esperti che ci lavorano. Quindi dovrebbe essere un ottimo ambiente per introdurre unit test / test di integrazione. Perché non funziona per noi? Come l'hai fatto funzionare nella tua azienda?

Non li definirei "sviluppatori esperti", se si rifiutano di fare unit test. Ci sono molti grandi articoli sui vantaggi positivi dei test (test sia di unità che di integrazione) e alla fine si riduce a quanto costa un bug alla tua azienda . Ad esempio, lavoro in un'azienda in cui la qualità è importante, quindi i test unitari e di integrazione sono inevitabili. Puoi facilmente trovare molti articoli che indicano che solo i test unitari stanno riducendo il numero di bug del 30%! (In realtà, è nell'intervallo 20-90%, in media il 30%, ma è ancora molto.)

Per farlo funzionare nella tua azienda, assumere un consulente o assegnare questo compito a un ingegnere senior (impiegherà un po 'di tempo per farlo). E poi, costringere tutti a rispettare le regole.


20
Devo sottolineare che praticamente TUTTO funziona "Se fatto correttamente". Tuttavia, ciò non è molto utile per tutti, ma una piccolissima minoranza di qualsiasi popolazione. Affinché un processo sia davvero in grado di affermare che funziona, deve anche funzionare quando fatto "sorta di".
Dunk

11
Sottolineerò che l'eccessiva generalizzazione della situazione di ognuno alla propria (vale a dire che non li definirei "sviluppatori di buona esperienza" .. questioni di qualità) non solo dimostra la vostra mancanza di ampiezza di esperienza ma non è molto produttiva. Ogni settore ha la propria definizione di "opere"; e quali test di laurea devono essere fatti a livello di unità, integrazione e sistema. Molti sviluppatori "eccezionalmente bravi" sono giunti alla conclusione che i test unitari offrono un vantaggio economico rispetto ai test di integrazione automatizzati. Si rendono anche conto che questo probabilmente vale solo per il loro settore specifico.
Dunk

11
"Non li definirei" sviluppatori esperti ", se si rifiutassero di fare unit test." Questo è solo l'errore di No True Scotsman. L'industria del software è andata avanti per decenni senza test unitari e la maggior parte di quell'industria continua ad andare d'accordo senza di essa oggi. Potrebbe essere una buona idea ma semplicemente non è obbligatorio.
Noah Yetter,

1
"non perdere tempo con i test unitari": lo riformulo come "non perdere tempo con test unitari inutili". I test unitari alla cieca possono portare a una perdita di tempo enorme.
Giorgio,

1
@Dunk Odio davvero l'intero fenomeno TDD prima di tutto, ma non posso essere d'accordo con la tua prima affermazione. O stai facendo una cosa giusta o non lo sei. Puoi fare bene un test unitario e magari vederne i meriti, ma non vedrai mai i meriti di nessuna cosa fatta a metà del culo.
Erik Reppen,

10

Sono molti dei motivi per cui l'introduzione del test automatico potrebbe non riuscire. Penso che si riduca al fatto che i programmatori tendono a non cambiare le loro abitudini di codifica e non sono pienamente in grado di abbracciare i test unitari.

Molte persone che vogliono iniziare con i test automatizzati provano a introdurli per una base di codice esistente. Proveranno a scrivere test di integrazione che testano contemporaneamente molte funzionalità dell'applicazione esistente. Tali test di integrazione sono notoriamente troppo difficili e troppo costosi da mantenere. Consiglio: introdurre test automatici per una nuova base di codice.

I test unitari sono buoni test da automatizzare. Tutto quanto sopra (test di integrazione, test dei componenti, test di sistema) può anche essere testato automaticamente, ma il rapporto costi-benefici diminuisce rapidamente quanto più funzionalità viene testata contemporaneamente. Questo effetto negativo viene amplificato se si costruiscono tali test su funzionalità scarsamente testate dall'unità. Consiglio: introdurre test automatici a livello di test unitari e costruire test di integrazione automatizzati su una solida base di test unitari .

Dai punti precedenti gran parte del successo dei test automatici dipende dall'efficacia dei test unitari. Hai test unitari efficaci se ti senti produttivo con test unitari. Quando le persone iniziano con i test unitari, tendono ad adeguare il loro codice esistente e le loro abitudini di codifica in test unitari. Ironia della sorte, questo è il modo più difficile per apprendere i test unitari. Inoltre, il test unitario richiede di modificare il modo in cui si codifica (ad esempio l'applicazione dei principi SOLID ). La maggior parte dei programmatori presto smette di scrivere test unitari perché pensa che la curva di apprendimento sia troppo ripida e trova imbarazzante avvolgere i test unitari attorno a un codice progettato non così testabile. Consiglio: apprendi i test delle unità da zero con un nuovo codice e affronta il fatto che devi modificare le tue abitudini di codifica.

Ci sono molti altri fattori, ma ho scoperto che per la maggior parte dei programmatori è problematico cambiare il loro modo di scrivere codice. Il codice scritto senza test sembra diverso. Se non riesci a comprimere il tuo codice in un progetto testabile, molto probabilmente non riuscirai a scrivere test unitari efficaci. Ciò distrugge il terreno per test automatici efficaci.

L'ho sperimentato da solo e ora sono felice di lavorare in un'azienda che ha introdotto con successo test automatizzati. Potrei scrivere molto di più sugli altri fattori, ma penso che le abitudini di codifica e i test unitari siano i più importanti. Fortunatamente ci sono altri che hanno più esperienza di me e riempiono i libri con il loro know-how. Uno di questi libri è Brownfield Application Development in .NET, che posso davvero consigliare, dal momento che stai utilizzando lo stack della tecnologia Microsoft.


Introduce automated tests on the unit test level and build automated integration tests on a solid foundation of unit tests.+1
c69

10

Una cosa che non ho visto chiaramente affrontata nelle risposte sopra è che i test unitari sono essenzialmente un bene pubblico e un costo privato. Ho scritto un post sul blog qui .

Ciò che ne consegue è che mentre una serie di test avvantaggia il team o un singolo sviluppatore, scrivere il test è un costo per chi lo fa, il più delle volte.

In breve, a meno che la scrittura del test non sia forzata in qualche modo - e le risposte sopra elencate elencano un numero di modi diversi per farlo - non c'è motivo per un singolo sviluppatore di farlo.

In un'azienda in cui ho lavorato, la scrittura di unit test era una parte necessaria per la fornitura di una funzione. Il nuovo codice non è stato accettato a meno che un unit test facesse parte del commit o di una nuova funzionalità: sono state eseguite brevi revisioni del codice per ogni "compito" assegnato a uno sviluppatore. Potrebbe essere utile attuare una politica simile sul posto di lavoro.


8

È interessante notare che il business è più pro-testing rispetto agli sviluppatori! Mi sembra che la tua più grande sfida sarà superare la resistenza dei tuoi sviluppatori al cambiamento; devono ridefinire la propria comprensione del proprio lavoro per includere test unitari.

Nulla può aiutarti di più dei primi successi di unit test per aiutare i tuoi sviluppatori a superare la loro resistenza a scrivere questi test. Se li spingi a fare qualcosa di nuovo, assicurati di spingere prima per qualcosa con una ricompensa quasi garantita.

@SkipHuffman ha toccato questo, ma lo dirò apertamente. Alcune cose sono molto più adatte ai test automatizzati di altre. Per il primo passaggio, NON testerei il database o l'interfaccia utente. L'input da un database può essere estremamente difficile da configurare e demolire. I test di output dell'interfaccia utente tendono a essere rapidamente interrotti dall'aspetto e dai cambiamenti che sono completamente irrilevanti per i test.

Quello che definirei "middleware" è perfetto per i test unitari. Codice che ha chiaramente definito le condizioni di input e output. Se segui il principio DRY (Don't Repeat Yourself), avrai scritto alcune piccole classi o funzioni per risolvere problemi ricorrenti che sono unici per la tua applicazione.

I test unitari sono un ottimo strumento per limitare il rischio di cambiare i componenti interni esistenti. Scrivi test unitari prima di cambiare un componente interno che ha funzionato a lungo. Questi test dimostrano che la funzionalità attualmente funzionante è preservata. Dopo aver apportato la modifica e aver superato tutti i test unitari, sai di non aver interrotto nulla "a valle". Se trovi un problema a valle, aggiungi un test unitario per esso!

Ron Heifitz direbbe di "affrontare i conflitti nei valori che le persone detengono o di ridurre il divario tra i valori che le persone rappresentano e la realtà che affrontano. Il lavoro adattivo richiede un cambiamento di valori, credenze o comportamenti". Dopo aver superato la resistenza umana al cambiamento, è possibile diramare in aree di test più difficili, a seconda dei casi.


6
"superare la resistenza dei tuoi sviluppatori al cambiamento": non tutte le resistenze sono senza motivo e non si dovrebbe evitare una discussione onesta usando l'argomento "resistenza al cambiamento".
Giorgio,

7

Una cosa sui test automatizzati è che richiede di scrivere codice per essere testabili. Questa non è una cosa cattiva in sé e per sé (in effetti è buona perché scoraggia molte pratiche che come regola dovrebbe essere evitata), ma se stai cercando di applicare i test unitari al codice esistente, allora è probabile che non lo sia stato scritto in modo verificabile.

Cose come singoli, metodi statici, registri, localizzatori di servizi e così via introducono dipendenze che sono molto difficili da deridere. Le violazioni della Legge di Demetra significano che troppe parti della tua base di codice sanno troppo su come funzionano altre parti della tua base di codice, introducendo ulteriori dipendenze nascoste che possono essere difficili da rompere. Tutte queste cose rendono difficile isolare un modulo dal resto della base di codice e se non riesci a testare i tuoi moduli in isolamento, i test unitari perdono molto del loro valore. Se un test ha esito negativo è a causa di un errore nell'unità in prova, o a causa di un errore in una delle sue dipendenze, o forse è perché i dati che vengono trasferiti attraverso un'origine dati dipendente non sono quelli previsti dal test writer ? Se puoi'

La maggior parte delle codebase che ho visto che non sono state costruite pensando ai test unitari tendono ad essere intrinsecamente non verificabili, poiché i programmatori tendono a concentrarsi sul far funzionare il codice come si aspettano, piuttosto che fare il lavoro necessario per mantenere l'accoppiamento libero e le dipendenze esplicite . Il codice che è stato scritto pensando ai test unitari tende ad apparire molto diverso.

Molte persone adottano un approccio ingenuo ai test unitari quando iniziano a farlo per la prima volta, pensano di poter semplicemente scrivere un sacco di test per una base di codice esistente e tutto andrà bene, ma non funziona mai così a causa di i problemi sopra menzionati. Iniziano a scoprire di dover disporre di quantità eccessive di configurazione nei test unitari per farli funzionare affatto, e i risultati sono spesso discutibili perché la mancanza di isolamento nel codice significa che non è possibile rintracciare ciò che ha causato un fallimento del test. Tendono anche a iniziare a provare test "intelligenti" che dimostrano alcuni aspetti altamente astratti di come dovrebbe funzionare il sistema. Questo tende a fallire perché un test di unità "intelligente" è una potenziale fonte di bug in sé. Il test ha avuto esito negativo a causa di un bug nel modulo testato, o a causa di un bug nel test? Un test dovrebbe essere così lancinante semplice che ovviamente non c'è alcuna possibilità che un bug possa nascondersi al suo interno. In effetti i test migliori sono raramente più lunghi di 2 righe, la prima riga indica all'unità sottoposta a test di fare qualcosa, la seconda afferma che ciò che ha fatto è stato quello che ci si aspettava.

Se il tuo team è seriamente intenzionato ad adottare i test unitari, non sarebbe saggio iniziare con un progetto esistente. I progetti esistenti del tuo team sono probabilmente non verificabili senza importanti refactoring. Stai meglio usando un nuovo progetto come base per apprendere i test unitari, dato che hai una lavagna pulita con cui lavorare. È possibile progettare la nuova base di codice per favorire l'iniezione di dipendenze su singoli, registri e altre dipendenze nascoste, è possibile scrivere per dipendere dalle interfacce anziché dalle implementazioni e così via. Puoi anche (e dovresti) scrivere i test a fianco del codice da testare, poiché la scrittura dei test in seguito porta a test unitari che assicurano che il modulo testato faccia quello che pensi possa essere fatto invece di quelli che testano che lo fa cosa dicono le specifiche che dovrebbe fare.

Una volta acquisita una certa confidenza con i test unitari, il tuo team probabilmente inizierà a rendersi conto dei difetti nel loro codice esistente che costituiranno ostacoli ai test unitari. Questo è quando puoi iniziare a lavorare per refactificare il codice esistente per renderlo più testabile. Non essere ambizioso e cerca di farlo tutto in una volta, o prova a sostituire un sistema che funziona con uno completamente nuovo, inizia semplicemente trovando i bit della base di codice che possono essere facilmente testati (quelli che non hanno eventuali dipendenze o dove le dipendenze sono ovvie) e scrivere test per quelle. So di aver detto che scrivere un test a fianco del codice è preferibile a scrivere test dopo, ma anche un test scritto in seguito ha ancora valore come punto di partenza. Scrivi i test come se non sapessi nulla su come funziona la classe oltre a ciò che le sue specifiche dicono che dovrebbe fare. Quando si eseguono i test e si verificano errori, le specifiche o l'implementazione sono errate. Ricontrolla entrambi per determinare quale è sbagliato e aggiorna il test o il codice di conseguenza.

Una volta che hai raccolto il frutto basso, inizia il tuo vero lavoro. Devi iniziare a trovare le dipendenze nascoste nella tua base di codice e correggerle, una alla volta. Non diventare troppo ambizioso a questo punto, basta attenersi a fare un modulo alla volta, o anche solo un singolo problema in un modulo, fino a quando gli ostacoli al test non vengono risolti e puoi passare al bit successivo.

TL: DR: la maggior parte delle persone pensa che i test siano facili e che tu possa adattarli facilmente al codice esistente. Entrambe queste ipotesi sono sbagliate. Se ti imbarchi in un progetto per ottenere unit testing nei tuoi progetti tenendo conto di entrambi questi fatti, avrai maggiori probabilità di avere successo.


suggerimento: metti il ​​TL; DR: in alto - ho dovuto leggere tutti i tuoi post solo per arrivarci! (che in qualche modo sconfigge il punto)
gbjbaanb,

4
  • C'è qualcuno nella tua azienda con una vasta esperienza nell'esecuzione di test automatizzati?

In caso contrario, le iniziative di test automatizzati probabilmente falliranno. Il test automatizzato è un'abilità, come molte altre abilità nella programmazione, e se non hai nessuno con esperienza nel farlo, non è facile dire se un test automatizzato è un buon test automatizzato con un valore reale, o uno cattivo che lo farà fallire casualmente / richiedere aggiornamenti frequenti / in realtà non esercita alcun codice interessante.

  • Qualcuno ha un potere di comando? Sono in grado di chiedere un cambiamento?

Se nessuno ascolta, non importa se dicono che il test non va bene. (Nota che il potere di comando non deve essere formalizzato. Anche avere una squadra che se ne frega è buono.)

  • Stai sviluppando strumenti e processi per semplificare l'implementazione e l'integrazione dei test automatizzati nel ciclo di sviluppo?

Gli sviluppatori sono pigri. Devi rendere le cose che vuoi che facciano facili da realizzare, e le cose che non vuoi che facciano più difficili da realizzare. È necessario assicurarsi che le librerie di test rendano più semplice eseguire le attività associate all'installazione e allo smontaggio del test, in particolare l'installazione relativa all'ambiente, come database di test o simili. (Deridere il database è discusso in alcuni di questi commenti, ma dovrebbe essere usato con cautela. Un database reale dovrebbe essere facile da girare e consente di testare l'interazione tra componenti e cicli di vita del processo, spesso più importante e più efficace del test unitario un singolo accessore di dati.)

Dovresti anche assicurarti che i tuoi IDE abbiano un buon modo per avviare la suite di test. Dovresti eseguire la suite di test spesso in modo che le persone se ne accorgano quando non fallisce piuttosto che lasciarla indugiare nella sofferenza. Gli sviluppatori rispondono bene anche al feedback, ad esempio un sistema di integrazione automatizzata che ripristina le loro modifiche se hanno superato un test. O, meglio, feedback positivo: un sistema di integrazione automatizzato che rileva i bug e ti evita di rompere le cose.


Non credo sia giusto dire che gli sviluppatori sono pigri. Forse è il caso della tua esperienza, ma sicuramente non è una verità universale.
Sam,

4

Innanzitutto, se i tuoi sviluppatori non vedono il valore dei tuoi test, probabilmente è perché i tuoi test non sono preziosi, non perché i tuoi sviluppatori sono ciechi al loro valore o al valore dei test in generale. Tra i suoi evangelisti, c'è la tendenza a credere che lo sviluppo guidato dai test non può fallire, può semplicemente essere fallito da sviluppatori pigri e pigri. Penso che sia sbagliato e controproducente.

Quando mi è stato presentato lo sviluppo guidato dai test, significava, in effetti, scrivere un test per verificare che un metodo che non fallirà mai. Il che è bello, all'inizio, perché ottieni un bel controllo verde e un senso di realizzazione. Più tardi, dopo aver riformulato il codice, hai decine di esasperanti X rosse, nessuna delle quali dice altro che il codice è cambiato, che i test non sono più validi e che hai perso molto tempo a scriverli.

Lo vuoi evitare.

Da allora ho adottato un approccio diverso ai test. Invece di una coppia di implementazione dell'interfaccia , ho un'interfaccia, un'implementazione, un test triplo . L'interfaccia specifica il comportamento, l'implementazione esegue il comportamento, il test controlla il comportamento.

Suppongo che sembri ovvio, ma per me distingue tra il codice che devi dimostrare funziona come specificato e il codice che puoi testare tanto o quanto meno ritieni appropriato. Il codice che devi dimostrare è l'interfaccia che offri all'esterno; il resto è solo la tua preoccupazione.

In questo caso, chiederei agli sviluppatori se vedono una divisione naturale nel codice in cui questo tipo di test sarebbe appropriato. Esiste un'interfaccia implementata dal team A e utilizzata dal team B? In tal caso, è nell'interesse del team B assicurarsi che l'interfaccia si comporti come si aspettano. Chiedere al team B di scrivere un test per questo, quindi dire al team A di assicurarsi che la loro implementazione sia conforme al test; o, in caso contrario, e intenzionalmente no, per discutere del cambiamento inatteso con l'altra squadra, in modo che possano prepararsi.

Penso che ciò illustrerebbe il valore del test. Non è fine a se stesso, nonostante i deliziosi controlli verdi. Esiste per rendere esplicita la promessa fatta da uno sviluppatore a un altro e per garantire che la promessa sia mantenuta in modo soddisfacente per entrambi.


1
Mi piace il codice che posso leggere meglio del codice che qualcuno riteneva necessario per essere testato fino alle minuzie del genere.
Erik Reppen,

1
Le adorabili zecche verdi che ritengo siano il problema: rendono il test una specie di gioco.
gbjbaanb,

2

L'aggiunta di numerosi test unitari a un grande progetto preesistente è un duro lavoro. Se hai già trovato un buon framework di derisione che funziona per te, dovresti aver risolto il problema più difficile.

Suggerisco di provare ad aggiungere test mentre aggiungi funzionalità / correggi bug. La correzione dei bug è la più semplice. Scrivi un test che fallisce a causa del tuo bug e poi correggi il bug. Allo stesso tempo, probabilmente ti ritroverai a scrivere alcuni test più semplici che superano. Ovviamente, vuoi davvero usare un po 'di codice piccolo e facilmente testato per questo.

Una volta che le persone iniziano ad abituarsi a scrivere test per le cose più semplici, si spera che trovino che scrivano il loro codice per essere più testabili.

Consiglierei anche di misurare la copertura del codice dei tuoi test (ho usato cobertura per Java in passato). Avrai bisogno di un server di integrazione continua che esegua i test e produca le metriche su base regolare (ogni giorno, ogni check-in). Se i tuoi colleghi sviluppatori sono entusiasti, vorranno vedere aumentare la copertura nel tempo e possono vedere i buchi di copertura spalancati in alcuni dei tuoi


2

Penso che potresti dover giocare il gioco lungo. Una cosa che puoi fare per ottenere una certa accettazione è tentare di testare in modo esaustivo l'unità la prossima funzione che scrivi e quindi tenere traccia del numero di bug nel tempo. Si spera che si scoprano che i principali bug verranno colti presto (in particolare se si accoppia questo con Test-Driven Design) e il numero di regressioni dovrebbe essere molto basso. Dopo un periodo di tempo, diciamo 1 anno, confronta le statistiche con funzionalità non unit testate di complessità simile. Se riesci a dimostrare che il numero di nuovi bug e regressioni è notevolmente inferiore, hai fornito una giustificazione finanziaria e diventa più difficile ignorare il team del prodotto.

Ho avuto una situazione in cui sono stato in grado di utilizzare TDD e test unitari per una caratteristica importante. Dopo la fine della fase di sviluppo non è stato segnalato un singolo bug in oltre 5 anni. Quando è stato richiesto un nuovo, e rischioso, miglioramento, sono stato in grado di implementarlo e catturare tutte le regressioni nei test unitari.


1

Sono fermamente convinto che il valore dei test unitari sia ampiamente sottovalutato da molti team a causa di diversi fattori, molti già evidenziati nelle risposte.

Spesso gli sviluppatori sono sotto pressione per "fare le cose", quindi provare che un blocco di codice funziona è una prova sufficiente per il cliente. Questo vale quasi sempre per la società di consulenza e il QA guidato dall'uomo: se il cliente non richiede test unitari e considera sufficiente una dimostrazione dal vivo, allora il cliente ha totalmente fallito poiché firmerà l'approvazione per il codice che potrebbe nascondere errori.

Spesso gli sviluppatori sono frustrati. Essere un programmatore è un lavoro duro: finire un'attività e passare alla prossima è soddisfacente, quindi tutti vogliono sbrigarsi e finire. Fino a quando non vengono colpiti da un autobus con un grosso bug che sale mesi dopo il QA originale. In questo scenario, il controllo qualità automatico e continuo è un problema di gestione piuttosto che per gli sviluppatori (verranno comunque pagati per il loro lavoro, forse per gli straordinari).

Ma c'è un'eccezione

Sono fermamente convinto che l'accettazione del modello di test automatizzato sia una funzione della "umanità" dei test in corso. Se stai testando un modulo web con un front-end, è più probabile, nonostante strumenti come il selenio, riempire il modulo da solo, vedere il risultato e credere nel determinismo. Ti dimenticherai di rieseguire i test più tardi o sarai troppo pigro per ripetere i vecchi test, ed è per questo che a volte i bug vengono scoperti in seguito. Per sfruttare questo, una forte modularizzazione del codice e rigide regole sulla "modifica del vecchio codice" sono state dimostrate accettabili in un ambiente bancario (nella mia esperienza di lavoro personale).

Invece, se lo sviluppatore è incaricato di sviluppare un modulo di dati altamente automatizzato e ad alto volume, sarà più probabile che scriva test unitari approfonditi e li invii ai lotti di test. Questo perché riempire un grande payload XML con i dati convertiti da un'origine dati esterna (beffarda o no) non è un lavoro soggetto a problemi umani. Alcuni sviluppatori di test alla fine costruiranno un front-end piccolo e divertente per questo specifico tipo di test. Quando ho lavorato alla tesi del mio Master, stavo lavorando su un bus di registrazione che gestiva oltre 6000 messaggi syslog al secondo e dovevo misurare la perdita di pacchetti e la corruzione: ho naturalmente scritto unità e stress test per quasi tutti i componenti, in particolare il parser Syslog.

Al fine di rendere gli sviluppatori più inclini al test unitario

Credo che debbano essere costretti a farlo. Se sei un cliente intelligente, dovrai richiedere ai tuoi consulenti di eseguire l'intera suite di test in ogni QA. Se sei un buon team leader, potresti pensare di assegnare la seguente attività a uno sviluppatore intelligente: costruisci una piattaforma di test interni. Ciò non ha nulla a che vedere con l'antipasto della piattaforma con effetti interni, ma è invece un insieme di classi di supporto, simulazioni di database, configurazioni, parser, convertitori, coltelli dell'esercito svizzero per aiutare gli sviluppatori a costruire test in pochissimo tempo.

Le piattaforme di test attuali come NUnit sono di uso generale e consentono di verificare affermazioni generiche. L'uso corretto dell'iniezione di dipendenza e delle fabbriche specifiche del progetto aiutano gli sviluppatori a scrivere meno codice per i test e ad essere più felici. Non ho ancora avuto la possibilità di sperimentarlo su un progetto completo, non posso fornire feedback sulla vita reale.


1

I test automatizzati sono come lo sviluppo di software. Sfortunatamente le persone che assumi per i test sono originariamente destinate a scrivere casi di test, piani, strategie, seguire il processo di revisione, testare manualmente e registrare i bug.

Non appena ricevono le responsabilità dei test automatizzati, include una certa quantità di sviluppo software. Il trucco qui è che i test automatizzati, indipendentemente dagli strumenti che usi (e per l'amor del cielo non sostengono questo punto), necessitano di manutenzione e aggiornamento su base giornaliera. Quando gli sviluppatori cambiano codice,

  • è necessario assicurarsi che i test vengano mantenuti in esecuzione.
  • È necessario assicurarsi che i test non vengano rimossi poiché non sono stati eseguiti
  • le metriche di test devono mostrare ciò che hai eseguito sull'ultima build e su questa build. Per garantire che il numero di casi di test non si stia riducendo.
  • i casi di test devono essere rivisti allo stesso modo dello sviluppo per garantire che le persone non stiano rovinando, un po 'rompendo 1 test su 2 solo per aumentare i numeri (alcune volte i test sono esternalizzati, quindi questo monitoraggio è importante)
  • è molto più importante una comunicazione "sana" tra dev e test
  • mantenere non-functionalseparati i test e non aspettarsi che vengano eseguiti quotidianamente, ci vuole tempo per mantenerli aggiornati e buoni. Ma non arrenderti, assicurati che vengano mantenuti.

Fallisci a causa di questi motivi

  • i tuoi ingegneri di test sono ingegneri di test manuali senza capacità analitiche. non conoscono la differenza tra a ife un whileciclo. Poiché francamente nessun corso insegna test automatizzati, insegnano solo test manuali.
  • i tecnici addetti ai test sono troppo impegnati a testare manualmente le build e a registrare i bug in modo da perdere traccia dei test automatizzati
  • i responsabili dei test non si occupano delle metriche dei test automatici, solo perché mostrano dati non validi (all'avvio del progetto) e non mettono lo sforzo o la priorità negli standup e nelle riunioni quotidiane per sottolineare quanto sia importante rendere operativa l'automazione
  • si sceglie di automatizzare i test per le applicazioni mobili, che hanno una durata molto breve. al momento in cui scrivi, stabilizza la suite di test automatizzata che cambia i requisiti delle tue applicazioni, invece dovresti concentrarti sul test dei tuoi servizi web che eseguono la tua applicazione
  • non capisci che il team di test automatizzato segue la stessa pietra miliare: team di sviluppo, funzionalità complete, codice completo, blocco del codice e blocco del codice.
  • non si fa distinzione tra persone di test manuali e persone di test automatizzate.
  • entrambi ricevono lo stesso stipendio e riferiscono allo stesso manager, idealmente dovrebbero riferire al manager degli sviluppatori e i loro stipendi dovrebbero corrispondere a quelli dello sviluppo.
  • in realtà pensi e credi che junit non sia sufficiente per lo sviluppo di test automatizzati :).

Questi provengono dalla mia esperienza di lavoro per aziende che prendono molto sul serio i test automatizzati e comprendono che dev è importante come ingegneri di test automatizzati. E dalla mia esperienza di lavoro per persone che non lo sanno, capisci la differenza, non importa quanto spieghi loro.


Nel caso di test di unità e integrazione, le persone che dovrebbero scrivere i test sono gli sviluppatori, non i "tecnici di test" separati. (Come scritto nella domanda, il QA, vale a dire gli ingegneri di test, attualmente utilizza già test UI automatizzati.)
Paŭlo Ebermann,

Realisticamente parlando, chiunque scriva test automatici dovrebbe avere capacità di sviluppo.
Siddharth,
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.