Domande su TDD e test di unità

6

Sono uno sviluppatore di software junior e ho fatto ricerche su alcune delle pratiche del settore per migliorarmi. Ho esaminato brevemente le unit test e non riesco a vedere come il tempo extra di scrittura di una tonnellata di unit test renderà il mio codice migliore.

Per mettere le cose in prospettiva:

  1. I progetti su cui lavoro sono piccoli
  2. Sono l'unico sviluppatore del suddetto progetto (di solito)
  3. I progetti sono tutte applicazioni su misura

La cosa che non ottengo di più è, come può un test unitario dirmi se la mia funzione di calcolo dei prezzi (che può dipendere da cose come il giorno della settimana e le festività bancarie ecc., quindi assumere 20-40 linee per quella funzione) è corretta? Non sarebbe più veloce per me scrivere tutto il codice e il sit attraverso una sessione di debug per testare ogni fine del codice?

Sarebbe gradito qualsiasi esempio basato su moduli (gli esempi che ho visto dai video MSDN sono tutti MVC e una perdita di tempo IMHO).

    
posta Stuart Blackler 17.07.2011 - 18:08
fonte

5 risposte

23

The thing I don't get the most is, how can a unit test tell me whether my calculate price function (which can depend on things like the day of the week and bank holidays etc, so assume 20-40 lines for that function) is correct? Would it not be quicker for me to write all the code and the sit through a debugging session to test every eventually of the code?

Facciamo questo l'esempio. Se ti siedi e scrivi quello (chiamiamolo) metodo a 30 righe, proverai a pensare a tutte le possibilità, scriverle nel metodo, poi eseguirne il debug, cercando ancora di prendere in considerazione tutte le possibilità. Se sei andato a controllare per giorni della settimana e sei andato in vacanza, e hai trovato un bug, allora devi cambiare il metodo, e sarebbe facile cambiarlo in modo che ora funzioni correttamente per i giorni festivi, ma non per i fine settimana, ma dal momento che hai già controllato i fine settimana e ha funzionato, potresti dimenticarti di ripetere l'esame. Questo è solo uno scenario in cui gli errori si insinuano nel tuo prodotto con il tuo approccio.

Un altro problema è che può essere facile aggiungere codice per condizioni che non si verificano mai in effetti, a causa di un'eccessiva cautela. Qualsiasi codice non necessario aggiunge complessità al progetto e la complessità rende più difficile il debug e altre attività di manutenzione.

In che modo TDD ti protegge da questi problemi? Inizi a scrivere il caso più semplice e il codice più semplice che lo supererà. Supponiamo che il tuo prezzo predefinito sia $ 7. Scriverò questo Java-ish, perché è comodo, ma l'approccio funziona in qualsiasi lingua:

public void testDefaultPrice() throws Exception {
    assertEquals(7, subject.getPrice());
}

public int getPrice() {
    return 7;
}

Semplice come può essere, giusto? Incomplete, ma corrette fin dove siamo andati.

Ora diremo che il prezzo del weekend deve essere $ 9. Ma prima che possiamo arrivarci, dobbiamo sapere quali giorni costituiscono il fine settimana.

public void testWeekend() throws Exception {
    assertTrue(Schedule.isWeekend(Weekday.Sunday));
}

public boolean isWeekend(Weekday.Day day) {
    return true;
}

Fin qui tutto bene - e ancora molto incompleto.

public void testWeekend() throws Exception {
    assertTrue(Schedule.isWeekend(Weekday.Sunday));
    assertTrue(Schedule.isWeekend(Weekday.Saturday));
    assertFalse(Schedule.isWeekend(Weekday.Monday));
}

public boolean isWeekend(Weekday.Day day) {
    return day == Weekday.Sunday || day == Weekday.Saturday;
}

Aggiungi tutte le affermazioni di cui hai bisogno per essere sicuro di aver guidato il metodo alla correttezza.

Ora torna alla nostra classe originale:

public void testDefaultPrice() throws Exception {
    assertEquals(7, subject.getPrice());
}

public void testWeekendPrice() throws Exception {
    subject.setWeekday(Weekday.Sunday);
    assertEquals(9, subject.getPrice());
}

public int getPrice() {
    if (Schedule.isWeekend(day))
        return 9;
    return 7;
}

E così via. Si prega di notare, inoltre, come stiamo testando il design del nostro codice qui, e quanto è meglio per questo. Con il tuo approccio, la maggior parte dei programmatori avrebbe costruito il codice di test del fine settimana nel corpo di getPrice() , ma quello è il posto sbagliato. Un sacco di codice potrebbe voler sapere se un giorno è nel fine settimana; in questo modo lo hai in un unico luogo ben testato. Ciò promuove il riutilizzo e migliora la manutenibilità.

    
risposta data 17.07.2011 - 19:19
fonte
11

"sedersi attraverso una sessione di debug per testare ogni fine del codice?" potrebbe essere più veloce ...

La prima volta.

Quando devi tornare indietro e cambiare qualcosa, dovresti avere un'altra sessione. Poi, due settimane dopo, vogliono che qualcos'altro sia cambiato e dovrai fare un'altra sessione.

Dopo il primo cambiamento, e talvolta anche subito dopo lo sviluppo iniziale, il tempo di test accumulato è ora nel tempo che sarebbe stato necessario per scrivere i test unitari iniziali ed estenderli ad ogni modifica per quel cambiamento specifico. Le unit test possono darti la sicurezza di cambiare codice complesso (non complicato!) E sapere che non hai infranto nessuna delle funzionalità attuali.

    
risposta data 17.07.2011 - 18:26
fonte
3
  1. Probabilmente non sarà più veloce per te usare il debugger e il passo attraverso ogni condizione e tracciare gli input e gli output.
  2. Quello che ottieni è un test che puoi continuare a eseguire in futuro dopo ogni modifica apportata al tuo codice. Di ', aggiungi un nuovo condizione per la funzione di calcolo del prezzo in futuro e capita di invertire una delle altre condizioni del software dipende - il test unitario fallito sarebbe la tua salvezza. Non dovresti pensare a saltare nel debugger e testare di nuovo ogni condizione.

IMHO è davvero difficile valutare il valore dei test unitari nella tua posizione, soprattutto perché sei l'unico a lavorare sui tuoi progetti.

Vorrei provare un libro per ulteriori dettagli sui vantaggi e le tecniche di test:

link

    
risposta data 17.07.2011 - 18:19
fonte
0

Bene che hai chiesto :) Allora perché TDD? Puoi provare a rispondere alle seguenti domande per vedere se riesci ad apprezzare i motivi del TDD.

  1. Il progetto è piccolo. Vuol dire che conosci ogni minima parte della logica che sta dietro la funzionalità che hai scritto e il motivo per cui lo hai codificato?
  2. Se la tua risposta è sì, proviamo a fare un ulteriore passo avanti accoppiando l'altro fatto che hai affermato - sei uno sviluppatore solitario nel tuo progetto - SOLO. Pensi che ricorderesti sempre perché hai una logica di codice in atto ogni volta che la guardi?
  3. La tua risposta è sì, prendiamola un po 'oltre. Quanto tempo ci vuole per ricordare la risposta per l'ultima domanda?

A questo punto, spero che otterresti l'immagine. Se non l'hai fatto, ecco di cosa si tratta - il tuo codice di test agirà come un'integrazione che puoi fare rapidamente riferimento, per scoprire perché una particolare logica è in atto. Questo aiuta la tua produttività e sarebbe un'esperienza piacevole rispetto alle sessioni di debugging lunghe e faticose.

Oltre a tutto ciò, le seguenti sono le altre ragioni del perché pratichi TDD:

  1. PROVE CONFORME AL CODICE CHE SCRIVI. Aiuta non solo te in un secondo momento, ma qualsiasi sviluppatore che dovesse lavorare al progetto, per capire lo scopo di un particolare pezzo di codice.
  2. Scrivendo test che programmi in modo difensivo. Potrebbero esserci situazioni in cui vorresti ri-fattorizzare il codice o aggiungere nuove funzionalità o correggere qualche bug. È la suite di test che (se scritta correttamente) ti proteggerà dal bug sfortunato che viene attivato da una condizione, in produzione (che avresti per qualche motivo non testato in ambienti non di produzione). È una cosa sgradevole ottenere i bastion da tutti gli angoli quando qualcosa va storto nella produzione e di solito lo fa. Come otteniamo il più possibile l'evento ZERO. OTTIENI LA DIFESA. SCRIVI IL GIUSTO SET DI PROVE.
  3. A lungo termine, la codifica difensiva migliora la qualità del codice e aumenta la produttività.
  4. I test sono metodi più veloci per test di routine manuali basati su alcuni check list. Il test manuale potrebbe essere esplorativo - testare cose insolite. I test delle tue unità funzionano come Suite di regressione per i tuoi test sui fumi. Puoi riferirti alla persona leggendaria, Bliki di Martin Fowler sul test delle unità per ulteriori informazioni su questo.
  5. Se esegui il purista TDD - prima i test di scrittura e poi il codice, avrai una migliore comprensione di ciò che scrivi e assicurati di scrivere solo il codice necessario. Sperimenterai anche miglioramenti del design evolutivo guidati dai test.
risposta data 17.07.2011 - 19:58
fonte
0

... my calculate price function (which can depend on things like the day of the week and bank holidays etc, so assume 20-40 lines for that function)

Data la natura volatile del codice (le regole di prezzo possono essere cambiate frequentemente - e così è il test), si vuole rendere il test a buon mercato, ma non si deve saltare del tutto il test.

Se più di un condizionale ( if-then-else ) può essere vero in qualsiasi momento, concentrati sul test delle conseguenze inattese delle combinazioni di regole .

Lo scopo è impedire al tuo programma di arrivare a una risposta assurda. Mentre ogni regola di determinazione dei prezzi può essere corretta quando giudicata da sola, le loro combinazioni possono produrre risultati inattesi, come l'applicazione di uno sconto due volte laddove era proibito, o la conversione di uno sconto in un sovrapprezzo.

Il modo in cui mi avvicinerei è:

  • Crea una tabella di "casi di test" che vuoi coprire. Il set di casi di test dovrebbe esercitare ciascuna delle tue regole di calcolo dei prezzi e anche le loro combinazioni. Rimuovi i casi ritenuti ripetitivi o assurdi.
  • Per i casi rimanenti, prova a calcolare il prezzo che ti aspetteresti, a mano. Devi esercitare il tuo buon senso a questo punto: se le regole tariffarie fornite dal tuo manager arrivano a una risposta assurda, le regole potrebbero essere errate o che si tratti di una conseguenza imprevista di alcune combinazioni di regole.
  • Quando hai finito, esegui i test case attraverso il tuo codice. Stampa l'output del programma e controlla se c'è qualche errore.
  • Se non ci sono errori, converti il tuo programma di test in un test unitario affermando i valori di uscita previsti. Questo aiuta a prevenire i bug da future modifiche al codice.
risposta data 17.07.2011 - 22:27
fonte

Leggi altre domande sui tag