2009-06-19 21 views
10

Sto provando a praticare TDD.Scoperta di altri oggetti durante il TDD

La mia comprensione è che TDD dovrebbe andare in questo modo

  1. Scrivi un elenco di test per l'interfaccia/classe che sto per svilupparsi.
  2. Inizia con il test più semplice non implementato dalla mia lista di test.
  3. Scrivi il test, nessun codice di implementazione ancora.
  4. Scrivere l'interfaccia della classe per compilare il codice.
  5. Eseguire il test risultante in un test non riuscito.
  6. Scrivere l'implementazione facendo passare il test.
  7. Rifattore il casino che ho fatto.
  8. Goto 2.

Il problema che ho è quando si scrive l'attuazione o fare il refactoring. Vengo spesso alla conclusione che l'implementazione che ho appena scritto dovrebbe essere delegata ad un'altra classe.

Cosa dovrebbe fare un vero TDD'r a questo punto?

  1. Lascia l'elenco dei test esistente da solo per un po 'e creare una nuova per la classe appena scoperto (lo stesso problema può manifestarsi in sede di attuazione della nuova classe offcourse)
  2. fare la fine di interazione Sulla base di testare e simulare la nuova classe, continuare con i test della classe su cui si sta lavorando e tornare più tardi per creare un'implementazione corretta della classe derisa.
  3. Questa situazione non dovrebbe presentarsi. Probabilmente non ho pensato abbastanza bene al mio progetto iniziale. (ma non sarebbe quello di sconfiggere uno degli scopi di TDD ?!).

Mi piacerebbe sapere come le altre persone gestiscono queste situazioni.

risposta

9

Non cercare una relazione uno a uno tra i test e le classi. Se decidi di introdurre una nuova classe, lascia che sia un refactoring supportato dal test originale e aggiungi i test nella posizione appropriata (dove dipende dal caso specifico) quando vuoi aggiungere funzionalità (o per testare le eventualità di cui hai bisogno per coprire ciò che non hai ancora testato).

Vorrei aggiungere che il successo principale in TDD è quello di entrare nel ritmo del refattore rosso-verde. Quando senti il ​​beneficio di quel ritmo, hai iniziato a "prenderlo". Ciò non significa che lo si possa trovare utile in tutti i casi, ma finché non si sente quel ritmo non si è arrivati ​​a ciò che piace ai suoi sostenitori.

E di solito c'è (specialmente in applicazioni architettonicamente complicate, come le applicazioni n-tier) una certa quantità di progettazione anticipata. Niente di abbozzato nella pietra, ma abbastanza per dare alle unità un posto dove andare. Naturalmente l'architettura può evolvere in una metodologia agile, ma un'idea generale del paesaggio deve essere presente se ci sono più livelli nell'architettura.

MODIFICA: (In risposta al commento). La nuova classe dovrebbe essere testata a pieno titolo? Non necessariamente.Dipende se la classe sviluppa un'importanza propria. Quando si esegue un test unitario, si sta testando una funzionalità. Non è un test di integrazione solo perché ci sono due classi coinvolte. Diventa un test di integrazione quando due unità iniziano a interagire. Il confine che di solito penso è se devo impostare uno stato significativo nel gruppo di classi A per interagire con il gruppo di classi B, e specialmente se il gruppo di classi A chiama il gruppo di classi B e che cosa Sono interessato a testare come B ha reagito ad A, quindi sto osservando un test di integrazione.

+1

Ma le nuove classi dovrebbero essere testate di per sé, no? Se il design ti guida verso un punto in cui ti piace creare più classi di "supporto", il test unitario con cui hai iniziato sta diventando un test di integrazione. –

1

È necessario creare una classe di simulazione. Una singola interfaccia con risultati prevedibili. Quindi puoi testare l'originale.

In seguito, è possibile ripetere la procedura con la nuova classe.

+1

In realtà questo è quello che penso che dovrei fare, ma là fuori, c'è una guerra santa in corso su "state based" vs "interaction based testing". Non mi piace il fatto che questa soluzione leghi i tuoi test a una particolare dichiarazione di un'interfaccia che usi. Nei test basati sullo stato, posso modificare la dichiarazione dell'interfaccia della classe di supporto (molto probabilmente) senza dover cambiare i miei testcases. Utilizzando test basati sull'interazione, devo cambiare anche i test. –

2

Quando mi imbatto in questa situazione, seguo la soluzione numero 1. Continua a ricorrere, facendo tutte le classi che ritieni appropriate, finché non hai una raccolta di implementazioni di cui sei soddisfatto. Con l'esperienza scoprirai che i tuoi progetti riflettono la tua esperienza e questo genere di cose non accadrà più.

+0

Questo è più o meno quello che sto facendo ora, ma non mi piace il fatto che ti distolga dalla classe che stavi testando. Dopo un po 'torni in quella classe e prova a capire da dove sei partito. –

+1

Come ha detto Yishai, non dovresti pensare in termini di classi di test. Stai testando le implementazioni di soluzioni ai problemi e se l'implementazione si verifica su più classi, va bene. –

6

Il problema che ho è che quando ho arrivo al punto 6 & 7, ad un certo punto nel tempo ho sempre giunto alla conclusione che l'attuazione ho appena scritto dovrebbe essere delegato alla un'altra classe.

Realizzare il tuo design sarebbe meglio con una classe diversa - questo è il design, ed è questo il punto di TDD. Quindi è una cosa bella, e non dovrebbe infastidirti.

Ma ti dà fastidio. Quindi che si fa? Riconoscere che la delega a un'altra classe è un refactoring; questo è qualcosa che deve essere fatto dopo il passaggio 6, durante il passaggio 7. Una volta che sei verde, refactoring per un design migliore. Hai già ottenuto i test per la nuova classe; sono solo collegati per chiamare la classe originale. Va perfettamente bene Dopo aver estratto la classe e delegato, se ti sentiresti più a tuo agio nel test, chiama direttamente la classe estratta: vai a cercarla. Nessun danno. Se la classe estratta inizia ad essere utilizzata da altri chiamanti, la consiglierei e forse quando inizi a chiamarla da altre classi è un buon momento per farlo (ma se ti infastidisce ora, fallo ora).

+0

Molto pragmatico, grazie. –

Problemi correlati