TDD, nuovi test mentre quelli vecchi non ancora implementati


13

Sto sperimentando uno sviluppo guidato dai test e ho scoperto che spesso arrivo a una situazione simile:

  1. Scrivo test per alcune funzionalità X. Quei test falliscono.
  2. Durante il tentativo di implementare X, vedo che devo implementare alcune funzionalità Y in un livello inferiore del mio codice. Così...
  3. Scrivo test per Y. Ora entrambi i test per X e Y falliscono.

Una volta avevo lavorato su 4 funzionalità in diversi livelli di codice contemporaneamente e stavo perdendo la mia attenzione su quello che sto effettivamente facendo (troppi test falliti contemporaneamente).

Penso di poter risolvere questo problema impegnandomi maggiormente nella pianificazione dei miei compiti ancor prima di iniziare a scrivere test. Ma in alcuni casi non sapevo che avrei dovuto approfondire, perché ad esempio non conoscevo molto bene l'API del livello inferiore.

Cosa devo fare in questi casi? TDD ha qualche consiglio?

Risposte:


9

La cosa buona è che ti rendi conto che il tuo codice sotto test ha bisogno di assistenza. Invece di implementarlo immediatamente, crea un'interfaccia e usa i mock per assicurarti che i tuoi test taggino il codice corretto. Dopo aver superato questi test, è quindi possibile passare all'implementazione del codice su cui si basa.


I miei test di solito non hanno conoscenza di cosa dovrebbe fare un metodo internamente (ad esempio quale API di livello inferiore chiamare). Devo solo regolare i test per deridere tutto ciò di cui ho bisogno nel codice testato?
liori,

2
Allo stesso modo, le tue classi testate non dovrebbero preoccuparsi di ciò che fanno gli "strati inferiori". Usa mock / stub al posto di classi / oggetti reali. Ciò potrebbe richiedere un po 'più di impegno nella progettazione, ma risulta in un codice meno accoppiato e più facile da riutilizzare.
Mchl

1
Stai usando l'iniezione di dipendenza? In questo modo puoi facilmente separare le preoccupazioni di livello inferiore dalle classi di livello superiore. La tua classe sotto test ha un costruttore con parametri per le sue dipendenze (come interfacce) nel tuo test crei simulazioni per le interfacce. Fondamentalmente stai fingendo di aver già implementato i servizi di livello inferiore.
Michael Brown,

@ Mike Brown, sì, lo faccio. So di poter creare oggetti finti. Ma poi nel mio test per funzionalità Xdevo sapere quale parte delle dipendenze di cui Xho bisogno per deridere. Sento che questo fa parte dei dettagli di implementazione, che non dovrebbero far parte dei test, altrimenti potrei dover cambiare i test mentre refactoring l'implementazione. Dovrei preoccuparmene?
liori,

1
Niente affatto ... i test dovrebbero riflettere i presupposti del sistema in esame. Ti aiuta anche a scoprire ciò di cui hai bisogno dai servizi su cui si basa il sistema. Sono stato d'accordo con te su questo argomento, ma lo paragono a come ho capito la programmazione ricorsiva. Per prima cosa scrivi il codice assumendo che tu abbia una funzione che fa quello che vuoi. Quindi scrivi il codice che fa quello che vuoi.
Michael Brown,

4

Stub e mock possono essere usati per simulare la funzionalità che non è ancora stata modificata / implementata. Possono anche aiutarti a risolvere le dipendenze che causano questo tipo di "reazione a catena".

D'altra parte, forse tenere solo un test (fallito) che guida il cambiamento successivo è l'approccio migliore.

Altri test mirati al codice che si basa su nuove funzionalità possono essere temporaneamente disabilitati in quanto non sono realmente rilevanti a questo punto, ad es. nel tuo caso, disabilitare i test per X fino a quando non si implementa Y ecc.

In questo modo puoi concentrarti solo sul prossimo cambiamento, che è quello che vuoi, credo.


Ah, ho cercato una funzione per disattivare un test durante un test all'interno del mio IDE e non ne ho trovato uno. Ora ho scoperto che Python unittestha già saltato i test. Questo potrebbe essere abbastanza per me.
liori,

Usiamo google test C ++ framework - e ha un'opzione per disabilitare i test. I test disabilitati non vengono eseguiti ma compilati - nel momento in cui ne hai bisogno - sono lì pronti per essere eseguiti (inoltre puoi 'forzare l'esecuzione' dei test disabilitati - tipo di 'abilitazione run-time') - funzionalità eccellente ...
ratkok

3

Fermare

A prima vista sembra che qui possano esserci due problemi separati:

  1. hai dimenticato alcune storie e scenari di prova e non le hai scoperte fino a quando non hai iniziato a lavorare su un particolare scenario di prova e / o

  2. stai effettivamente effettuando test di unità e non test di funzionalità TDD

Per # 1, fermati , torna indietro e aggiorna le storie e prova gli scenari, quindi ricomincia da capo con uno scenario diverso.

Per # 2, fermati e ricorda che stai testando le funzionalità, non le unità, quindi utilizza le simulazioni per sorvolare altre interfacce e / o implementa più codice per far passare il test senza aggiungere nuovi scenari di test. Ciò presuppone che non manchino scenari di test, ma invece - e questo è davvero comune - test unit unit e TDD.


Mi piace molto la tua risposta, fa un lavoro migliore nello spiegare cosa sta realmente succedendo.
maple_shaft

... Detto questo, non conosco un PM al mondo che non perderà completamente la testa alla frase "STOP, dobbiamo tornare indietro". Tenteranno di sacrificare il loro primogenito all'altare per far andare avanti il ​​progetto, il debito tecnico e i test unitari incompleti saranno dannati. Immagino che non si possa incolparli quando la loro unica metrica in un'organizzazione è quella di portare a termine il progetto in tempo. Alcune organizzazioni apprezzano solo il tempo rispetto alla qualità ed è per questo che probabilmente non ho mai visto TDD lavorare con successo in questo tipo di organizzazioni, che purtroppo è la maggior parte delle quali IMO.
maple_shaft

@maple_shaft: il tempo che ti fermi per riorganizzarti potrebbe essere solo di poche ore - a meno che il tuo processo non sia molto lontano dalla base, nel qual caso fermarti per qualche giorno per riportarlo in pista renderà molto più probabile che il progetto avrà successo. Non ha senso andare a tutto vapore lungo la strada sbagliata!
Steven A. Lowe,

0

Questa è un'ottima domanda e un'enorme frustrazione anche per me con TDD. Mi sento come se TDD manchi in questo scenario in cui non hai modo di sapere quali componenti o funzionalità di livello inferiore ti serviranno prima di iniziare a sviluppare.

Personalmente ho scoperto che TDD funziona solo se sai esattamente cosa devi fare e cosa devi chiamare per eseguire una funzione. Gli sviluppatori non sanno sempre tutto prima di iniziare, quindi ho scoperto che il modo migliore per me stesso di mitigare la situazione che descrivi:

Prototipo

Quando creo semplici prototipi di app per esplorare e scoprire metodi e approcci a un problema tecnico, scopro molto del lavoro delle gambe e toglio quella ricerca prima di iniziare. Anche la progettazione e la stima diventano molto più semplici.

Se il prototipo deve essere così coinvolto da diventare l'applicazione, allora ti esorto a non fare la cosa pigra e costruire test unitari per il tuo prototipo dopo il fatto.

A quel punto dovresti sapere di più sull'API di livello inferiore ed essere in grado di deridere con successo l'API di livello inferiore nei componenti di livello superiore.


Quindi in realtà stai suggerendo di ottenere maggiori informazioni per la fase di pianificazione eseguendo alcuni codici esplorativi in ​​modo informale (= non seguendo una metodologia formalizzata). E quindi supponi che fornirà informazioni sufficienti per pianificare il codice reale. Ho ragione?
liori,

Perché supponi che la prototipazione sia un processo informale? Ogni stima dovrebbe tenere conto della prototipazione e le pianificazioni del progetto dovrebbero tener conto di tale compito, nonché di un compito di sviluppo necessario. Lo vedo allo stesso modo di Design o Code-Review. In tale nota, è formalizzato e dovrebbe essere tenuto in considerazione, ancora di più per compiti con molte incognite. Senza prototipazione e capacità di eseguire Proof-of-Concept, perseguire TDD presuppone che gli sviluppatori sappiano TUTTO su QUALCOSA con TUTTE le funzionalità. Il mondo reale non funziona in questo modo e non mi interessa quanto tu sia intelligente o esperto.
maple_shaft

Per "modo informale" non intendevo dire che il tempo per la prototipazione non dovrebbe essere preso in considerazione, ma che mentre fai i prototipi, non segui TDD o qualsiasi altra metodologia di codice.
liori,

TDD è una metodologia per unit test e sviluppo. Avrebbe senso fare TDD per la revisione del codice? TDD ha senso per la progettazione, la scrittura di specifiche tecniche o la lavagna? Il prototipo è un compito di per sé, un tipo esplorativo di sviluppo per la ricerca, la dimostrazione del concetto e l'educazione.
maple_shaft

1
TDD ha perfettamente senso per la prototipazione. Ti consente di esporre rapidamente tutto ciò che è (oggetto, funzione, API, intero programma) sotto forma di un insieme di requisiti ripetibili ed eseguibili. Fatevi un favore e leggete il software orientato agli oggetti in crescita guidato da test ; ti guida passo dopo passo nella costruzione di un'intera applicazione (inclusa l'integrazione) in un modo test-first.
Frank Shearar,

0

Dipende dal tipo di test che stai scrivendo mentre fai TDD.

Il modello classico è quello di scrivere test unitari e usare mock o stub per separare il test dalle altre "unità" di codice.

Esistono molti altri modelli alternativi come ATDD in cui il test è uno stack completo o un test dello stack quasi completo. In questo caso particolare i tuoi test di scrittura che affermano il comportamento del programma richiesto non una singola unità di codice, in modo da non scrivere altri test. Si otterrebbe l'attrezzo il roundtrip per soddisfare il test. Quindi aggiungi altri test per altre caratteristiche / comportamenti.

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.