Perchè i test unitari non vengono visti come negativi?

88

In alcune organizzazioni, apparentemente, parte del processo di rilascio del software consiste nell'utilizzare il test delle unità, ma in qualsiasi momento devono passare tutti i test delle unità. Ad esempio potrebbe esserci una schermata che mostra tutti i test unitari che passano in verde, che dovrebbe essere buono.

Personalmente, penso che non è così che dovrebbe essere per i seguenti motivi:

  1. Promuove l'idea che il codice dovrebbe essere perfetto e non dovrebbero esistere bug - che nel mondo reale è sicuramente impossibile per un programma di qualsiasi dimensione.

  2. È un disincentivo pensare a test unitari che falliranno. O sicuramente escogitare test unitari che sarebbero difficili da risolvere.

  3. Se in qualsiasi momento passano tutti i test unitari, non c'è una grande immagine dello stato del software in qualsiasi momento. Non esiste una roadmap / obiettivo.

  4. Distacca i test delle unità di scrittura in anticipo, prima dell'implementazione.

Suggerirei persino che persino il rilascio di software con test dell'unità guasti non sia necessario. Almeno allora sai che alcuni aspetti del software hanno delle limitazioni.

Mi sto perdendo qualcosa qui? Perché le organizzazioni si aspettano che tutti i test unitari passino? Non è questo vivere in un mondo da sogno? E in realtà non scoraggia una vera comprensione del codice?

    
posta user619818 22.05.2018 - 12:32
fonte

17 risposte

263

Questa domanda contiene IMHO su molti fraintendimenti, ma il principale su cui vorrei concentrarmi è che non distingue tra rami di sviluppo locali, tronco, stadiazione o rami di rilascio.

In un ramo di sviluppo locale, è probabile che ci siano alcuni test dell'unità guasti in qualsiasi momento. Nel bagagliaio, è accettabile solo in parte, ma già un strong indicatore per risolvere le cose al più presto. Tieni presente che i test dell'unità guasti nel bagagliaio possono disturbare il resto della squadra, poiché richiedono a tutti di verificare se l'ultima modifica non ha causato l'errore.

In un ramo di staging o release, i test falliti sono "allerta rossa", mostrando che c'è stato qualcosa di completamente sbagliato in qualche changeset, quando è stato unito dal tronco al ramo di rilascio.

I would even suggest that even releasing software with failing unit tests is not necessary bad.

Il rilascio di software con alcuni bug noti al di sotto di una certa gravità non è necessariamente negativo. Tuttavia, questi problemi noti non dovrebbero causare un test dell'unità guasto. Altrimenti, dopo ogni prova di unità, si dovranno esaminare i 20 test unitari falliti e controllare uno a uno se l'errore è accettabile o no. Questo diventa ingombrante, soggetto a errori e scarta una grande parte dell'aspetto dell'automazione dei test unitari.

Se hai davvero dei test per bug noti e accettabili, usa la funzione disable / ignore dello strumento di test dell'unità (in modo che non vengano eseguiti di default, solo su richiesta). Inoltre, aggiungi un ticket a bassa priorità al tuo tracker dei problemi, in modo che il problema non venga dimenticato.

    
risposta data 22.05.2018 - 13:48
fonte
227

... all unit tests passing in green - which is supposed to be good.

È è buono. No "dovrebbe essere" a riguardo.

It promotes the idea that code should be perfect and no bugs should exist - which in the real world is surely impossible for a program of any size.

No. Dimostra che hai testato il codice e puoi farlo fino a questo punto. È del tutto possibile che i tuoi test non coprano ogni caso. In tal caso, eventuali errori verranno visualizzati nei report dei bug e si scriveranno test [in errore] per riprodurre i problemi e quindi correggere l'applicazione in modo che i test vengano superati.

It is a disincentive to think up unit tests that will fail.

I test negativi o negativi pongono dei limiti fermi su ciò che la tua applicazione non accetterà e non accetterà. La maggior parte dei programmi che conosco obietteranno a una "data" del 30 febbraio. Inoltre, gli sviluppatori, i tipi creativi che siamo, non vogliono rompere "i loro bambini". L'attenzione che ne deriva sui casi di "percorso felice" porta a domande fragili che si interrompono, spesso.

Per confrontare la mentalità dello sviluppatore e del tester:

  • Uno sviluppatore si ferma non appena il codice fa ciò che vuole.
  • Un tester si interrompe quando non è più possibile interrompere il codice.

Queste sono radicalmente diverse prospettive e una che è difficile per molti sviluppatori riconciliarsi.

Or certainly come up with unit tests that would be tricky to fix.

Non scrivi test per farti da solo. Scrivi test per assicurarti che il tuo codice stia facendo ciò che deve fare e, cosa più importante, che continua per fare ciò che dovrebbe fare dopo hai cambiato la sua implementazione interna.

  • Il debug "dimostra" che il codice fa quello che vuoi che oggi .
  • I test "dimostrano" che il codice ancora fa ciò che vuoi nel tempo .

If at any point in time all unit tests pass, then there is no big picture of the state of the software at any point in time. There is no roadmap/goal.

L'unico test "immagine" ti dà un'istantanea che il codice "funziona" nel momento in cui è stato testato. Come si evolve dopo che è una storia diversa.

It deters writing unit tests up-front - before the implementation.

Questo è esattamente ciò che dovresti fare. Scrivi un test che fallisce (perché il metodo che sta testando non è ancora stato implementato) quindi scrivi il codice del metodo per far funzionare il metodo e, quindi, il test pass. Questo è praticamente il punto cruciale di Test-Driven Development.

I would even suggest that even releasing software with failing unit tests is not necessary bad. At least then you know that some aspect of the software has limitations.

Il rilascio del codice con test non funzionanti significa che alcune parti della sua funzionalità non funzionano più come prima. Potrebbe essere un atto deliberato perché hai corretto un bug o migliorato una funzionalità (ma dovresti aver prima modificato il test in modo che non ci sia riuscito, quindi aver codificato la correzione / miglioramento, facendo funzionare il test nel processo). Ancora più importante: siamo tutti umani e commettiamo errori. Se si interrompe il codice, è necessario interrompere i test e quei test non funzionanti dovrebbero impostare squilli di allarme.

Isn't this living in a dream world?

Se non altro, vive in Real World , riconoscendo che gli sviluppatori non sono né onniscienti né infallibili, che noi fanno commettiamo errori e che abbiamo bisogno di una sicurezza net per catturarci se e quando fai fa casino!
Inserisci test.

And doesn't it actually deter a real understanding of code?

Forse. Non è necessario necessariamente comprendere l'implementazione di qualcosa da scrivere per testarlo (questo è parte del problema). I test definiscono il comportamento e i limiti dell'applicazione e garantiscono che quelli rimangano gli stessi a meno che non li si modifichi deliberatamente.

    
risposta data 22.05.2018 - 13:08
fonte
31

Why are unit tests failing seen as bad?

Non lo sono: lo sviluppo basato su test è basato sulla nozione di test falliti. Fallire test di unità per guidare lo sviluppo, in mancanza di test di accettazione per guidare una storia ....

Quello che ti manca è context ; dove sono consentiti i test unitari per fallire?

La solita risposta è che i test di unità possono fallire solo nelle sandbox private.

La nozione di base è questa: in un ambiente in cui vengono condivisi test non validi, è necessario uno sforzo ulteriore per capire se una modifica al codice di produzione ha introdotto un nuovo errore. La differenza tra zero e non zero è molto più facile da rilevare e gestire rispetto alla differenza tra N e non N.

Inoltre, mantenere pulito il codice condiviso significa che gli sviluppatori possono rimanere in attività. Quando unisco il tuo codice, non ho bisogno di spostare i contesti dal problema che sto pagando per risolvere per calibrare la mia comprensione di quanti test dovrebbero fallire. Se il codice condiviso sta passando tutti i test, qualsiasi errore che appare quando mi unisco alle mie modifiche deve essere parte dell'interazione tra il mio codice e la linea di base pulita esistente.

Allo stesso modo, durante l'imbarco un nuovo sviluppatore può diventare produttivo più rapidamente, poiché non è necessario dedicare del tempo a scoprire quali test non sono accettabili.

Per essere più precisi: la disciplina è che i test eseguiti durante la build devono passare.

C'è, come meglio posso dire, niente sbagliato con test falliti disabilitati .

Ad esempio, in un ambiente di "integrazione continua", condividi il codice su cadenza elevata. Integrare spesso non significa necessariamente che i tuoi cambiamenti debbano essere pronti per il rilascio. Esiste un vasto assortimento di tecniche di schieramento oscuro che impediscono il rilascio del traffico in sezioni del codice finché non sono pronte.

Quelle stesse tecniche possono essere utilizzate anche per disabilitare i test falliti.

Uno degli esercizi che ho seguito su un punto di rilascio riguardava lo sviluppo di un prodotto con molti test non riusciti. La risposta che ci è venuta in mente era semplicemente di passare attraverso la suite, disabilitando i test falliti e documentando ciascuno. Questo ci ha permesso di raggiungere rapidamente un punto in cui tutti i test abilitati stavano passando, e il donatore / proprietario dell'oro / gestore poteva vedere tutti i mestieri che avevamo fatto per arrivare a quel punto e prendere decisioni informate sulla pulizia rispetto a nuovi lavori.

In breve: ci sono altre tecniche per tracciare lavoro non eseguito che lasciare un sacco di test falliti nella suite in esecuzione.

    
risposta data 22.05.2018 - 14:37
fonte
25

Ci sono molte ottime risposte, ma vorrei aggiungere un altro punto di vista che ritengo non sia ancora ben coperto: che cosa è esattamente il punto di fare test.

I test unitari non sono lì per verificare che il tuo codice sia privo di errori.

Penso che questo sia il principale malinteso. Se questo fosse il loro ruolo, ci si aspetterebbe sicuramente di avere dei test falliti dappertutto. Ma invece,

I test unitari verificano che il tuo codice faccia quello che pensi che faccia.

In casi estremi potrebbe includere la verifica che i bug noti siano non risolti. Il punto è controllare la base di codice ed evitare modifiche accidentali. Quando apporti una modifica, va bene e in realtà ci si aspetta che rompa alcuni test - stai cambiando il comportamento del codice. Il test appena rotto è ora una buona traccia di ciò che hai cambiato. Controlla che tutte le rotture siano conformi a ciò che desideri dal tuo cambiamento. Se è così, basta aggiornare i test e andare avanti. In caso contrario, beh, il tuo nuovo codice è decisamente bacato, torna indietro e risolvilo prima di inviarlo!

Ora, tutto quanto sopra funziona solo se tutti i test sono verdi, dando un strong risultato positivo: questo è esattamente come funziona il codice. I test rossi non hanno questa proprietà. "Questo è ciò che questo codice non fa" è raramente una informazione utile.

I test di accettazione possono essere ciò che stai cercando.

Esiste un test di accettazione. Puoi scrivere una serie di test che devono essere soddisfatti per chiamare il prossimo traguardo. Questi sono ok per essere rossi, perché questo è quello per cui sono stati progettati. Ma sono cose molto diverse dai test unitari e non possono né dovrebbero sostituirli.

    
risposta data 22.05.2018 - 18:17
fonte
24

Lo vedo come l'equivalente software della sindrome della finestra rotta .

I test di funzionamento mi dicono che il codice è di una certa qualità e che i proprietari del codice si preoccupano di esso.

Per quanto riguarda quando dovresti preoccuparti della qualità, ciò dipende piuttosto da quale ramo / repository del codice sorgente stai lavorando. Il codice di sviluppo può benissimo avere dei test non funzionanti che indicano lavori in corso (si spera!).

I test interrotti su un ramo / repository per un sistema live dovrebbero immediatamente impostare squilli di allarme. Se i test interrotti possono continuare a fallire o se sono permanentemente contrassegnati come "ignorati", si aspettano che il loro numero aumenti nel tempo. Se questi non vengono revisionati regolarmente, è stato stabilito il precedente che va bene per i test non funzionanti.

I test non funzionanti sono visti in modo peggiorativo in molti negozi in modo da avere una restrizione sulla possibilità o meno di eseguire il commit di codice danneggiato .

    
risposta data 22.05.2018 - 14:54
fonte
11

Ecco l'errore logico sottostante:

If it is good when all tests pass, then it must be bad if any tests fail.

Con i test unitari, IS è buono quando passano tutti i test. È ANCHE BENE quando un test fallisce. I due non devono essere in opposizione.

Un test non riuscito è un problema che è stato catturato dagli strumenti prima che raggiungesse un utente. È un'opportunità per correggere un errore prima che venga pubblicato. E questa è una buona cosa.

    
risposta data 22.05.2018 - 19:47
fonte
9

La risposta di Phill W è fantastica. Non posso sostituirlo.

Tuttavia, voglio concentrarmi su un'altra parte che potrebbe aver fatto parte della confusione.

In some organisations, apparently, part of the software release process is to use unit testing, but at any point in time all unit tests must pass

"in qualsiasi momento" sta esagerando nel tuo caso. Ciò che è importante è che i test delle unità passino dopo una certa modifica è stata implementata, prima inizi a implementare un'altra modifica.
Questo è il modo in cui tieni traccia di quale modifica ha causato un bug. Se i test delle unità sono iniziati non avendo dopo implementato la modifica 25 ma prima implementando la modifica 26, allora sai che la modifica 25 ha causato il bug.

Durante l'implementazione di un cambiamento, ovviamente i test unitari potrebbero fallire; molto dipende da quanto è grande il cambiamento. Se sto ristrutturando una funzione di base, che è più di un piccolo aggiustamento, probabilmente interromperò i test per un po 'finché non avrò finito di implementare la mia nuova versione della logica.

Questo può creare conflitti come regole del team. L'ho incontrato in realtà qualche settimana fa:

  • Ogni commit / push causa una build. La build non deve mai fallire (se lo fa o qualsiasi test fallisce, lo sviluppatore impegnato è biasimato).
  • Si prevede che ogni sviluppatore trasmetta le proprie modifiche (anche se incomplete) alla fine della giornata, in modo che il team conduca la revisione del codice in mattinata.

Una regola andrebbe bene. Ma le regole non possono funzionare insieme. Se mi viene assegnato un importante cambiamento che richiede diversi giorni per completare, non sarei in grado di rispettare entrambe le regole allo stesso tempo. A meno che non commentassi i miei cambiamenti ogni giorno e li commettessi solo senza commenti dopo che tutto era stato fatto; che è solo un lavoro senza senso.

In questo scenario, il problema qui non è che i test unitari non hanno scopo; è che la azienda ha aspettative non realistiche . Il loro set di regole arbitrarie non copre tutti i casi e l'inosservanza delle regole è considerata ciecamente fallimento dello sviluppatore piuttosto che un fallimento di una regola (che è, nel mio caso).

    
risposta data 22.05.2018 - 15:57
fonte
6

Se non correggi tutti i test delle unità, puoi entrare rapidamente nello stato in cui nessuno risolve i test non funzionanti.

  1. Non è corretto poiché i test di unità trasmessi non mostrano che il codice è perfetto

  2. È un disincentivo creare un codice che sarebbe difficile da testare, il che è positivo dal punto di vista del design

  3. La copertura del codice può esserci di aiuto (anche se non è una panacea). Anche i test unitari sono solo un aspetto del test: anche tu vuoi test di integrazione / accettazione.

risposta data 22.05.2018 - 12:35
fonte
6

Per aggiungere alcuni punti alle risposte giuste ...

but at any point in time all unit tests must pass

Questo dimostra una mancanza di comprensione di un processo di rilascio. Un errore di test può indicare una funzionalità pianificata sotto TDD che non è ancora stata implementata; oppure può indicare un problema noto che ha una correzione pianificata per una versione futura; o potrebbe semplicemente essere qualcosa in cui la direzione ha deciso che questo non è abbastanza importante da risolvere perché è improbabile che i clienti se ne accorgano. L'aspetto chiave di tutto questo è che la direzione ha emesso un verdetto sul fallimento.

It promotes the idea that code should be perfect and no bugs should exist - which in the real world is surely impossible for a program of any size.

Altre risposte hanno coperto i limiti del test.

Non capisco perché pensi che eliminare gli errori sia un aspetto negativo. Se non vuoi consegnare il codice che hai controllato (al meglio delle tue capacità) fa quello che dovrebbe, perché lavori persino nel software?

If at any point in time all unit tests pass, then there is no big picture of the state of the software at any point in time. There is no roadmap/goal.

Perché deve esserci una roadmap?

I test unitari inizialmente verificano che la funzionalità funzioni, ma poi (come test di regressione) controllano che non si sia inavvertitamente rotto nulla. Per tutte le funzioni con test unitari esistenti, non esiste una roadmap . È noto che ogni funzione funziona (entro i limiti dei test). Se quel codice è finito, non ha una roadmap perché non c'è bisogno di più lavoro su di esso.

Come ingegneri professionisti, dobbiamo evitare la trappola della doratura. Gli hobbisti possono permettersi di sprecare tempo armeggiando intorno ai bordi con qualcosa che funzioni. Come professionisti, abbiamo bisogno di consegnare un prodotto. Ciò significa che otteniamo qualcosa di funzionante, verifichiamo che funzioni e passiamo al lavoro successivo.

    
risposta data 22.05.2018 - 16:34
fonte
6

It promotes the idea that code should be perfect and no bugs should exist - which in the real world is surely impossible for a program of any size.

Non è vero. perché pensi che sia impossibile? qui esempio per programma che funziona:

public class MyProgram {
  public boolean alwaysTrue() {
    return true;
  }

  @Test
  public void testAlwaysTrue() {
    assert(alwaysTrue() == true);
  }
}

It is a disincentive to think up unit tests that will fail. Or certainly come up with unit tests that would be tricky to fix.

In tal caso potrebbe non essere un test unitario, ma un test di integrazione se è complicato

If at any point in time all unit tests pass, then there is no big picture of the state of the software at any point in time. There is no roadmap/goal.

true, si chiama test unit per un motivo, controlla una piccola unità di codice.

It deters writing unit tests up-front - before the implementation.

Gli sviluppatori non dissuaderebbero a scrivere eventuali test se non ne comprendono i benefici per loro natura (a meno che non provengano dal QA)

    
risposta data 22.05.2018 - 12:44
fonte
4

It promotes the idea that code should be perfect and no bugs should exist

Sicuramente no. Promuove l'idea che i tuoi test non debbano fallire, niente di più e niente di meno. Supponendo che fare test (anche molti di loro) non dica nulla di "perfetto" o "nessun bug" è un errore. Decidere quanto dovrebbero essere superficiali o profondi i test è una parte significativa della scrittura di buoni test, e il motivo per cui abbiamo distinto distintamente categorie di test (test "unitari", test di integrazione, "scenari" in senso cetriolo ecc.).

It is a disincentive to think up unit tests that will fail. Or certainly come up with unit tests that would be tricky to fix.

Nello sviluppo basato su test, è obbligatorio che i test di unità ogni falliscano prima di iniziare a codificare. Si chiama "ciclo rosso-verde" (o "ciclo refactore rosso-verde") proprio per questo motivo.

  • Senza il test fallito, non si sa se il codice è effettivamente testato dal test. I due potrebbero non essere affatto correlati.
  • Cambiando il codice in esattamente fai virare il test da rosso a verde, niente di più e niente di meno, puoi essere abbastanza sicuro che il tuo codice fa quello che dovrebbe fare, e non un molto di più (che potresti non aver mai bisogno).

If at any point in time all unit tests pass, then there is no big picture of the state of the software at any point in time. There is no roadmap/goal.

I test sono più un tipo di micro-obiettivo. Nello sviluppo basato su test, il programmatore scriverà prima un test (singolare) e quindi avrà un chiaro obiettivo di implementare del codice; poi il prossimo test, e così via.

La funzione dei test non deve essere presente in modo completo prima della scrittura del codice.

Se eseguito correttamente, in una lingua e con una libreria di test che si adatta bene a questo approccio, questo può effettivamente accelerare notevolmente lo sviluppo, dal momento che i messaggi di errore (eccezioni / stacktraces) possono direttamente indirizzare lo sviluppatore a dove ha bisogno per eseguire il lavoro successivo.

It deters writing unit tests up-front - before the implementation.

Non vedo come questa affermazione sarebbe vera. I test di scrittura dovrebbero idealmente essere una parte dell'implementazione.

Am I missing something here? Why do organisations expect all unit tests to pass?

Perché le organizzazioni si aspettano che i test abbiano rilevanza per il codice. Scrivere test che abbiano esito positivo significa che hai documentato parte della tua applicazione e hai dimostrato che l'applicazione fa quello che dice (il test). Niente di più e niente di meno.

Inoltre, una parte molto importante dei test è la "regressione". Vuoi essere in grado di sviluppare o ridefinire il nuovo codice con sicurezza. Avere una grande quantità di test verdi ti permette di farlo.

Questo va dal livello organizzativo a quello psicologico. Uno sviluppatore che sa che i suoi errori saranno probabilmente catturati dai test sarà molto più libero di trovare soluzioni intelligenti e audaci per i problemi che deve risolvere. D'altra parte, uno sviluppatore che non ha test, dopo un po 'di tempo, si fermerà (a causa della paura) perché non saprà mai se una modifica che fa interrompe il resto dell'applicazione.

Isn't this living in a dream world?

No. Lavorare con un'applicazione basata sui test è pura gioia, a meno che non ti piaccia il concetto per qualsiasi motivo ("più sforzo" ecc. Ecc.) Che possiamo discutere in un'altra domanda.

And doesn't it actually deter a real understanding of code?

Assolutamente no, perché dovrebbe?

Trovate molti grandi progetti open source (per i quali la gestione della "comprensione" e del know-how sul codice è un argomento molto pressante) che effettivamente usano i test come la documentazione principale del software, a parte essendo test, forniscono anche esempi reali, funzionanti, sintatticamente corretti per utenti o sviluppatori dell'applicazione / libreria. Questo spesso funziona splendidamente.

Ovviamente, scrivere cattivi test è sbagliato. Ma questo non ha nulla a che fare con la funzione dei test di per sé.

    
risposta data 23.05.2018 - 11:14
fonte
3

(Dai miei commenti originali)

C'è una differenza tra funzionalità richieste e obiettivi futuri. I test sono per funzionalità richieste: sono precisi, formali, eseguibili e se falliscono il software non funziona. Gli obiettivi futuri potrebbero non essere precisi o formali, per non dire eseguibili, quindi è meglio lasciarli in linguaggio naturale come in issue / bug tracker, documentazione, commenti, ecc.

Come esercizio, prova a sostituire la frase "unit test" nella tua domanda con "errore del compilatore" (o "errore di sintassi", se non c'è compilatore). È ovvio che una versione non dovrebbe contenere errori del compilatore, dal momento che sarebbe inutilizzabile; tuttavia gli errori del compilatore e gli errori di sintassi sono il normale stato di cose sul computer di uno sviluppatore quando stanno scrivendo il codice. Gli errori scompaiono solo quando hanno finito; e questo è esattamente quando il codice deve essere premuto. Ora sostituisci "errore del compilatore" in questo paragrafo con "unit test":)

    
risposta data 23.05.2018 - 19:25
fonte
2

Lo scopo dei test automatici è dirti quando hai rotto qualcosa il prima possibile . Il flusso di lavoro ha un aspetto simile al seguente:

  1. Apporta una modifica
  2. Costruisci e metti alla prova le tue modifiche (idealmente automaticamente)
  3. Se i test falliscono, significa che hai rotto qualcosa che in precedenza funzionava
  4. se superano i test dovresti essere sicuro che la tua modifica non ha introdotto nuove regressioni (a seconda della copertura del test)

Se i tuoi test stavano già fallendo, il passaggio n. 3 non funziona in modo altrettanto efficace - i test falliranno, ma non sai se questo significa che hai rotto qualcosa o no senza indagare. Forse potresti contare il numero di test falliti, ma una modifica potrebbe risolvere un bug e romperne un altro, oppure un test potrebbe iniziare a fallire per un motivo diverso. Ciò significa che è necessario attendere un po 'di tempo prima di sapere se qualcosa è stato rotto, fino a quando tutti i problemi sono stati risolti o fino a quando ogni test fallito è stato studiato.

La possibilità per i test di unità di trovare bug appena introdotti il prima possibile è la cosa più preziosa dei test automatici: più a lungo un difetto non viene scoperto più è costoso ripararlo.

It promotes the idea that code should be perfect and no bugs should exist
It is a disincentive to think up unit tests that will fail

I test per cose che non funzionano non ti dicono nulla - scrivi test unitari per le cose che fanno funzionano, o che stai per risolvere. Ciò non significa che il tuo software sia privo di difetti, significa che nessuno dei difetti per i quali hai precedentemente scritto i test unitari è tornato di nuovo.

It deters writing unit tests up-front

Se funziona per te, scrivi i test in anticipo, ma non li controlli nel tuo master / trunk finché non passano.

If at any point in time all unit tests pass, then there is no big picture of the state of the software at any point in time. There is no roadmap/goal.

I test unitari non servono per impostare una roadmap / obiettivo, magari usare un backlog per questo? Se passano tutti i test, la "grande immagine" è che il software non è rotto (se la copertura del test è buona). Ben fatto!

    
risposta data 23.05.2018 - 22:30
fonte
2

Le risposte esistenti sono certamente buone, ma non ho visto nessuno affrontare questo malinteso fondamentale nella domanda:

at any point in time all unit tests must pass

No. Sicuramente, questo non sarà vero. Mentre sto sviluppando software, NCrunch è spesso marrone (errore di compilazione) o rosso (test fallito).

Dove NCrunch deve essere verde (tutti i test che passano) è quando sono pronto a inviare un commit al server di controllo del codice sorgente, perché a quel punto altri potrebbero prendere una dipendenza dal mio codice.

Ciò si alimenta anche nell'argomento della creazione di nuovi test: i test dovrebbero asserire la logica e il comportamento del codice. Condizioni al contorno, condizioni di errore, ecc. Quando scrivo nuove prove, cerco di identificare questi "punti caldi" nel codice.

I test unitari documentano come mi aspetto che venga chiamato il mio codice: precondizioni, risultati attesi, ecc.

Se un test si interrompe dopo una modifica, devo decidere se il codice o il test è in errore.

Come nota a margine, i test unitari vanno talvolta di pari passo con Test Driven Development. Uno dei principi di TDD è che i test non funzionanti sono le tue indicazioni. Quando un test fallisce, è necessario correggere il codice in modo che il test passi. Ecco un esempio concreto di questa settimana:

Sfondo : ho scritto e ora supporta una libreria utilizzata dai nostri sviluppatori che viene utilizzata per convalidare le query Oracle. Avevamo test che affermavano che la query corrispondeva a un valore atteso, il che rendeva il caso importante (non è in Oracle) e approvava allegramente delle query non valide purché corrispondessero completamente al valore previsto.

Invece, la mia libreria analizza la query utilizzando Antlr e una sintassi di Oracle 12c, quindi esegue il wrapping di varie asserzioni sull'albero di sintassi stesso. Cose del tipo, è valido (non sono stati generati errori di analisi), tutti i parametri sono soddisfatti dalla raccolta parametri, tutte le colonne previste lette dal lettore di dati sono presenti nella query, ecc. Tutti questi sono elementi che sono passati a produzione in vari momenti.

Uno dei miei colleghi ingegneri mi ha inviato una query lunedì che aveva fallito (o meglio, aveva avuto successo quando avrebbe dovuto fallire) durante il fine settimana. La mia libreria diceva che la sintassi andava bene, ma si è verificata quando il server ha cercato di eseguirlo. E quando ha esaminato la query, era ovvio il motivo:

UPDATE my_table(
SET column_1 = 'MyValue'
WHERE id_column = 123;

Ho caricato il progetto e aggiunto un test unitario che ha affermato che questa query non dovrebbe essere valida. Ovviamente, il test è fallito.

Successivamente, ho eseguito il debug del test non riuscito, ho fatto il punto del codice in cui mi aspettavo che generasse l'eccezione e ho scoperto che Antlr stava sollevando un errore sul paren aperto, ma non in un modo il codice precedente si aspettava. Ho modificato il codice, verificato che il test fosse ora verde (passando) e che nessun altro si fosse rotto nel processo, commesso e spinto.

Ci sono voluti 20 minuti, e nel processo ho effettivamente migliorato la libreria in modo significativo perché ora supportava un'intera gamma di errori che in precedenza ignorava. Se non avessi i test unitari per la biblioteca, la ricerca e la risoluzione del problema avrebbe potuto richiedere ore.

    
risposta data 24.05.2018 - 16:20
fonte
0

Un punto che non credo derivi da risposte precedenti è che c'è una differenza tra test interni e test esterni (e penso che molti progetti non siano abbastanza attenti a distinguere i due). Un test interno verifica che alcuni componenti interni stiano funzionando come dovrebbe; un test esterno mostra che il sistema nel suo complesso sta funzionando come dovrebbe. È possibile, ovviamente, avere errori nei componenti che non comportano un errore del sistema (forse c'è una funzionalità del componente che il sistema non usa, o forse il sistema si riprende da un errore del componente). Un errore di un componente che non determina un errore di sistema non dovrebbe impedirti di rilasciare.

Ho visto i progetti che sono paralizzati dall'avere troppi test dei componenti interni. Ogni volta che si tenta di implementare un miglioramento delle prestazioni, si interrompono decine di test, poiché si modifica il comportamento dei componenti senza effettivamente modificare il comportamento esternamente visibile del sistema. Ciò porta ad una mancanza di agilità nel progetto nel suo complesso. Credo che l'investimento in test di sistemi esterni abbia generalmente un payoff molto migliore dell'investimento nei test di componenti interni, specialmente quando si parla di componenti di livello molto basso.

Quando suggerisci che i test unitari falliti non contano davvero, mi chiedo se questo è quello che hai in mente? Forse dovresti valutare il valore dei test unitari e abbandonare quelli che causano più problemi di quanti ne valga, concentrandoti maggiormente sui test che verificano il comportamento visibile dall'esterno dell'applicazione.

    
risposta data 24.05.2018 - 15:43
fonte
0

"ma in qualsiasi momento tutti i test di unità devono passare"

Se questo è l'atteggiamento nella tua azienda, questo è un problema. In un determinato momento, ovvero quando dichiariamo che il codice è pronto per passare all'ambiente successivo, devono passare tutti i test unitari. Ma durante lo sviluppo, dovremmo aspettarci di routine che molti test unitari falliscano.

Nessuna persona ragionevole si aspetta un programmatore per ottenere il suo lavoro perfetto al primo tentativo. Quello che ci aspettiamo ragionevolmente è che continuerà a lavorarci fino a quando non ci saranno problemi noti.

"È un disincentivo pensare a test unitari che falliranno, o certamente proporre test unitari che sarebbero difficili da risolvere." Se qualcuno nella tua organizzazione pensa che non dovrebbero menzionare un test possibile perché potrebbe fallire e causare loro più lavoro per risolverlo, quella persona è totalmente non qualificata per il loro lavoro. Questo è un atteggiamento disastroso. Vorresti un dottore che dice "Quando faccio un intervento chirurgico, deliberatamente non controllo se i punti sono giusti, perché se vedo che non lo sono dovrò tornare indietro e rifarli e che rallenterà terminando l'operazione "?

Se il team è ostile ai programmatori che identificano gli errori prima che il codice vada in produzione, si ha un vero problema con l'atteggiamento di quella squadra. Se la direzione punisce i programmatori che identificano gli errori che rallentano la consegna, le probabilità sono che la tua azienda sia diretta al fallimento.

Sì, è certamente vero che a volte persone razionali dicono: "Ci stiamo avvicinando alla scadenza, questo è un problema banale e non vale la pena dedicare le risorse in questo momento per risolverlo". Ma non puoi prendere questa decisione in modo razionale se non lo sai. Esaminare freddamente un elenco di errori e assegnare priorità e programmi per risolverli è razionale. Deliberatamente rendersi ignoranti dei problemi in modo da non dover prendere questa decisione è sciocco. Pensi che il cliente non lo scoprirà solo perché non lo vuoi sapere?

    
risposta data 28.05.2018 - 01:17
fonte
-7

Questo è un esempio specifico di bias di conferma , in cui le persone tendono a cercare informazioni che confermino le loro convinzioni esistenti.

Un famoso esempio di ciò che sta accadendo è il gioco 2,4,6.

  • Ho una regola nella mia testa che qualsiasi serie di tre numeri passerà o fallirà,
  • 2,4,6 è un passaggio
  • puoi elencare gruppi di tre numeri e ti dirò se superano o falliscono.

La maggior parte delle persone sceglie una regola, ad esempio "il divario tra il 1 ° e il 2 ° numero è uguale al divario tra il 2 ° e il 3 °".

Verranno testati alcuni numeri:

  • 4, 8, 12? Passo
  • 20, 40, 60? Passo
  • 2, 1004, 2006? Passo

Dicono "Sì, ogni osservazione conferma la mia ipotesi, deve essere vera". E annuncia la loro regola alla persona che dà l'enigma.

Ma non hanno mai ricevuto un singolo "fail" per un gruppo di tre numeri. La regola avrebbe potuto essere "i tre numeri devono essere numeri" per tutte le informazioni che effettivamente hanno.

La regola è in realtà solo che i numeri sono in ordine crescente. Le persone in genere ottengono correttamente questo enigma solo se testano il fallimento. La maggior parte delle persone sbagliano, scegliendo una regola più specifica e testando solo i numeri che soddisfano questa regola specifica.

Per quanto riguarda il motivo per cui le persone cadono per pregiudizi di conferma, e possono vedere i test unitari fallire come prova di un problema, ci sono molti psicologi che possono spiegare una parzialità di conferma meglio di me, fondamentalmente si riduce a persone che non amano essere sbagliate e che lottano per cercare sinceramente di dimostrarsi sbagliato.

    
risposta data 23.05.2018 - 06:17
fonte

Leggi altre domande sui tag