Credo che per quello che vuoi veramente sapere, il tuo esempio non è adatto, quindi lascia che ne descriva uno migliore.
Ci sono diversi problemi di programmazione in cui l'implementazione più elegante e più breve non è quella che serve solo alcuni casi di test, ma quella che risolve il problema in modo più generale di quanto specificato dai test .
Ad esempio, è possibile implementare un algoritmo di ordinamento in modo incrementale scrivendo alcuni casi di test in modo TDD per ordinare due, tre o quattro elementi. Forse si inizia con un'implementazione che può solo ordinare due elementi, come
int[] Sort(int[] list)
{
// ... maybe some handling for lists with 0 or 1 element here ...
if(list[0]>list[1])
return new[]{list[1],list[0]};
else
return new[]{list[0],list[1]};
}
Ora, un test che passa 3 elementi in questa funzione fallirà. Tuttavia, quando estendete questo codice a 3, 4 o più elementi, raggiungerete rapidamente il punto in cui un algoritmo generale come un ordinamento di bolle o un ordinamento di inserimento (che funziona per lunghezze di lista arbitrarie) è più semplice di un'implementazione che funziona solo per un numero fisso di elementi. Infatti, facendo TDD, avresti potuto iniziare con un algoritmo complicato che confrontava fino a 4 elementi uno contro uno, ma nella fase di refactoring hai sostituito questo con un algoritmo di ordinamento più generale, che rende l'intero implementazione più semplice.
Ora non dovrebbe essere molto sorprendente quando aggiungi ulteriori test con più elementi, questi test non falliranno, anche se hai seguito tutte le regole TDD letteralmente, e anche se non hai implementato più codice del necessario per soddisfare tutti i test esistenti .
E sì, questo è un caso reale, molto più probabile che accada come questa risposta fa finta. Ho riscontrato questa situazione molte volte per tutti i diversi tipi di problemi nell'elaborazione delle stringhe, nella manipolazione degli insiemi, negli algoritmi matematici o geometrici: le implementazioni generali sono molto più semplici di quelle specializzate.
Quindi cosa si dovrebbe fare in questo caso? Tralasciando i test aggiuntivi con 5, 8 o 20 elementi, solo perché il codice "è già completo e i test aggiuntivi non inducono ulteriori modifiche al codice"? Non consiglierei questo: è ovviamente buono avere test aggiuntivi per un algoritmo complesso, ti darà molta più sicurezza nella correttezza del codice.
L'alternativa migliore qui è quella di rendere i test aggiuntivi falliti artificialmente per un breve periodo. Lo scopo principale di vedere i test che falliscono prima di passare a TDD è assicurarsi che il test sia effettivamente eseguito - è un "test per il test". Ad esempio, potresti aggiungere una frase come
if(list.Length>=5)
return null;
da qualche parte all'interno della funzione Sort
, e rimuoverlo dopo averlo visto fallito il test. Che prove i tuoi nuovi test sono effettivamente eseguiti, e non li hai mescolati con alcuni test esistenti.
Dato che hai chiesto un altro esempio: diciamo che hai una funzione
'string TrimNumeric(string value)'
che dovrebbe sostituire caratteri non numerici dall'inizio o alla fine della stringa di input value
e restituire il risultato. Quello che succede con i caratteri non numerici nel mezzo non è specificato finora. I seguenti casi di test stanno già passando:
Assert.AreEqual("123",TrimNumeric("abc123"));
Assert.AreEqual("123",TrimNumeric("123xyz"));
Assert.AreEqual("456",TrimNumeric("abc456xyz"));
Ora ottieni un ulteriore requisito: anche i caratteri non numerici nel mezzo devono essere eliminati. Inizi aggiungendo un test:
Assert.AreEqual("123",TrimNumeric("1a2b3cxyz"));
In tal caso, se non sai come viene implementato internamente TrimNumeric
, non c'è indicazione se questo test fallirà o meno. Infatti, se TrimNumeric
è stato implementato in modo semplice, semplice e generale, iterando su tutti i caratteri e mantenendo solo quelli numerici, è IMHO molto probabilmente questo test passerà immediatamente. Tuttavia dovrebbe essere chiaro il motivo per cui è necessario scrivere un tale test. Forse il test non passerà, se l'implementazione ha un aspetto diverso. Ma se passa fin dall'inizio, assicurati di farlo fallire almeno temporaneamente, per essere sicuro che venga eseguito.