TDD e controllo versione


25

Attualmente sto imparando il TDD e sto provando a metterlo in pratica nei miei progetti personali. Ho anche ampiamente utilizzato il controllo delle versioni su molti di questi progetti. Sono interessato all'interazione di questi due strumenti in un flusso di lavoro tipico, soprattutto quando si tratta di massimizzare gli impegni. Ecco alcuni esempi che vengono in mente:

  1. Inizio un nuovo progetto e scrivo un semplice test per creare una classe ancora inesistente. Devo eseguire il test prima di scrivere la classe anche se il test non viene nemmeno compilato? O dovrei stub fuori la quantità minima di codice necessario per compilare il test prima di eseguire il commit?

  2. Trovo un bug e scrivo un test per ricrearlo. Devo eseguire il test non riuscito o implementare la correzione dei bug e quindi eseguire il commit?

Questi sono i due esempi che mi vengono subito in mente. Sentiti libero di fornire ulteriori esempi nella tua risposta.

Modificare:

Ho ipotizzato in entrambi gli esempi che immediatamente dopo aver scritto il test scriverò il codice per far passare il test. Potrebbe anche verificarsi un'altra situazione: lavoro su un progetto usando TDD per diverse ore senza impegnarmi. Quando finalmente mi impegno, voglio dividere il mio lavoro in piccoli pezzi. (Git lo rende relativamente semplice anche se si desidera voler impegnare solo alcune delle modifiche in un singolo file.)

Ciò significa che la mia domanda riguarda tanto quanto cosa commettere quanto quanto quando commettere.

Risposte:


21

Devo eseguire il test prima di scrivere la classe anche se il test non viene nemmeno compilato? O dovrei stub fuori la quantità minima di codice necessario per compilare il test prima di eseguire il commit?

Ovviamente no. Dovresti completare sia il test che la classe. Commettere qualcosa che 1 non viene nemmeno compilato non ha senso e sicuramente farà arrabbiare le persone che lavorano allo stesso progetto se lo fai regolarmente.

Trovo un bug e scrivo un test per ricrearlo. Devo eseguire il test non riuscito o implementare la correzione dei bug e quindi eseguire il commit?

No, non eseguire un test non riuscito. La legge di LeBlanc afferma:

Più tardi è uguale a mai.

e il test potrebbe non riuscire a lungo. È meglio risolvere il problema non appena viene rilevato.

Inoltre, lo stile di sviluppo TDD dice:

Lo sviluppo guidato dai test ripete costantemente le fasi di aggiunta dei casi di test falliti, superandoli e refactoring.

Se si effettua il check in di un test non riuscito, significa che non è stato completato il ciclo.


1 Quando ho detto commit, intendevo davvero impegnarmi nel trunk (per gli utenti git, spingere le modifiche, in modo che altri sviluppatori le prendessero).


4
"e farà arrabbiare le persone che lavorano allo stesso progetto se" - qualcuno che vive nel mondo SVN usa GIT e non farai arrabbiare nessuno
Mateusz,

3
Penso che impegnarsi bene dopo aver scritto un test, non spingerlo fino a quando non hai finito.
Matsemann,

4
@radarbob Questo vale anche per un DVCS in cui esiste una distinzione tra impegno e spinta? Posso immaginare una situazione in cui eseguo diversi commit nel mio repository git locale in cui al commit finale la build non viene interrotta ma in uno qualsiasi dei commit temporanei potrebbe essere.
Code-Guru,

6
No, non eseguire test falliti. Ma uno dei punti di TDD è proprio quello di fare un test fallito prima della codifica. Quindi ha senso eseguire un test fallito.
mouviciel,

4
@ Code-Guru: per un DVCS, le regole dovrebbero essere: "Non commettere codice non funzionante in un ramo da cui gli altri estraggono regolarmente". Se gli altri non effettuano il pull dal tuo repository locale, questo può trovarsi in qualsiasi stato con cui puoi convivere.
Bart van Ingen Schenau,

6

Devo eseguire il test prima di scrivere la classe anche se il test non viene nemmeno compilato?

No.

Devo eseguire il test non riuscito

No.

Stai parlando di due paradigmi qui:

  1. sviluppo guidato dai test - che non dice nulla sul commit del codice. In effetti, ti dice su come scrivere il codice e quando hai finito. Quindi considererei ogni "fatto" come candidato per un impegno.
  2. sviluppo agile, in particolare: "impegnarsi presto e spesso" (che non richiede TDD). L'idea alla base è quella di avere una prima integrazione con altri componenti nel sistema e quindi ottenere un feedback precoce. Se ti impegni in un DVCS localmente e non spingi, è inutile in questo senso. Gli commit locali aiutano solo gli sviluppatori a strutturare il proprio lavoro.

La mia raccomandazione è: seguire la cerchia di TDD fino a quando il codice non viene compilato, i test sono verdi e hai qualcosa per contribuire al sistema. Pertanto, è necessario tagliare le funzionalità verticalmente, ad es. Per una nuova maschera dell'interfaccia utente non creare l'intero modulo e eseguire il commit senza la logica aziendale, ma piuttosto implementare un piccolo aspetto ma nel frontend e nella logica aziendale nonché nel livello di persistenza .

Per un bugfix di grandi dimensioni, eseguire il commit dopo ogni miglioramento (ad es. Refactoring), anche se il bug non è stato ancora risolto. I test dovrebbero essere verdi e il codice deve essere compilato, comunque.


5

Certamente inizi con l'uso di un controllo del codice sorgente sano come git.

Quindi puoi lavorare come preferisci e impegnarti in ogni angolo: ogni passo o sottofondo è un gioco equo.

Quindi, prima di spingere le cose, schiacci l'intero lavoro in un unico commit. O una coppia, nei punti in cui tutto è verde e la composizione ha un senso. E spingi questi impegni sensati. Per il caso multiplo, rendilo un ramo che unisci con --no-ff.

Il controllo del codice sorgente non è un sistema di tracciamento del lavoro o uno storico. Gli commit devono presentare un delta coerente sensibile, mentre almeno lo stato di checkout deve essere compilato. Gli intermedi possono essere conservati per un po 'a scopo di revisione, ma una volta che tutto è considerato a posto, un singolo commit per funzione è corretto.


5

È mia comprensione del mondo che uno si impegna a sottolineare un punto in cui potrebbe essere desiderabile tornare. Il punto a cui un test fallisce (ma compila) è sicuramente uno di questi punti. Se dovessi vagare nella direzione sbagliata cercando di fare un passaggio di prova, vorrei poter riportare il codice al punto di partenza e riprovare; Non posso farlo se non mi sono impegnato.


Sono d'accordo con te. Preferisco utilizzare un ramo diverso per seguire la regola "non interrompere la build" e unire le modifiche nel trunk solo quando il test viene superato.
Fil

5

Devo eseguire il test prima di scrivere la classe anche se il test non viene nemmeno compilato?

Con un SCM ramificato (ti ho visto usare Git) dovresti impegnarti ogni volta che vuoi un punto di backup ("Ho rovinato qualcosa; resetterò la directory di lavoro all'ultimo punto di backup") o quando hai una versione stabile. Quando hai una versione stabile (tutti i test superano), dovresti anche considerare di unire il ramo di funzionalità corrente nel tuo ramo di sviluppo principale.

O dovrei stub fuori la quantità minima di codice necessario per compilare il test prima di eseguire il commit?

A te (git ti dà la flessibilità di impegnarti quando vuoi senza influire sugli altri membri del tuo team o sulla tua capacità di lavorare su diverse funzionalità). Assicurati solo di non avere più funzioni incomplete (non funzionanti) nello stesso ramo contemporaneamente (quindi si bloccheranno a vicenda).

Trovo un bug e scrivo un test per ricrearlo. Devo eseguire il test non riuscito o implementare la correzione dei bug e quindi eseguire il commit?

Di solito faccio due commit per quello, a meno che il codice del test sia davvero piccolo / banale da scrivere.

Questi sono i due esempi che mi vengono subito in mente. Sentiti libero di fornire ulteriori esempi nella tua risposta.

Modificare:

Ho ipotizzato in entrambi gli esempi che, immediatamente dopo aver scritto il test, scriverò il codice per far passare il test.

Potrebbe essere un presupposto sbagliato da fare. Se lavori da solo (progetto personale) nulla ti impedisce di farlo sempre. In uno dei miei progetti di maggior successo (per quanto riguarda il mantenimento dell'elevata qualità del codice e del TDD durante lo sviluppo del progetto) abbiamo definito i test a volte settimane prima della loro attuazione (vale a dire dire che "il test" test_FOO_with_null_first_parameter "è ora definito come una funzione vuota e commettilo in questo modo. Quindi faremmo uno sprint (o mezzo sprint) a volte circa un mese dopo, solo per aumentare la copertura dei test per il modulo. Dato che avevamo già dichiarato i test, era facile stimare.

Potrebbe anche verificarsi un'altra situazione: lavoro su un progetto usando TDD per diverse ore senza impegnarmi. Quando finalmente mi impegno, voglio dividere il mio lavoro in piccoli pezzi. (Git lo rende relativamente semplice anche se si desidera voler impegnare solo alcune delle modifiche in un singolo file.) Ciò significa che la mia domanda riguarda tanto quanto cosa impegnare quanto quando si tratta di impegnarsi.

Direi sicuramente impegnarsi a creare punti di backup . Questo funziona molto bene per i test esplorativi ("Aggiungerò solo alcune stampe in tutta la base di codice, eseguirò e git reset --hardper rimuoverli quando avrò finito) e per la prototipazione.


2
Fai attenzione a raccomandare git reset --hard. È uno dei pochi comandi in git che ti farà perdere il lavoro.
gnash117,

2

Nel mio flusso di lavoro, quando possibile, faccio un lavoro incerto su un ramo personale di controllo delle fonti. Quindi posso provare, fallire, riprovare se necessario fino a quando non funziona e impegnarmi nel progetto più grande solo quando ho un vero codice di lavoro.

Dal punto di vista TDD, la domanda di "fai prima il check-in nel test?" dipende interamente dal codice su cui stai lavorando. Se si tratta di un nuovo codice, non esegui il check-in fino a quando non hai qualcosa che vale la pena fare il check-in. Ma se si tratta di un bug trovato nel codice già compilato o spedito, vale la pena fare il check-in in un test per riprodurre il bug, BY ITSELF. Soprattutto se è la fine di una giornata lavorativa, e lascerai l'ufficio prima di risolvere il codice.

(Ovviamente, se il tuo negozio ha un processo di compilazione automatizzato che si interrompe in caso di fallimento di alcuni test unitari, potresti non voler controllare un test fallito fino a quando non risolvi il bug. Ma quello sembra un modo strano di lavorare, dal momento che "trova e documentare i bug "e" correggere i bug "possono essere eseguiti da due team completamente diversi.)

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.