Lavoro spesso con programmi molto numerici / matematici, dove è difficile prevedere in anticipo il risultato esatto di una funzione.
Nel tentativo di applicare TDD con questo tipo di codice, trovo spesso la scrittura del codice in prova molto più semplice rispetto alla scrittura di unit test per quel codice, perché l'unico modo che conosco per trovare il risultato atteso è applicare l'algoritmo stesso (sia nel mio testa, su carta o al computer). Questo sembra sbagliato, perché sto effettivamente usando il codice in prova per verificare i test delle mie unità, invece del contrario.
Esistono tecniche note per scrivere unit test e applicare TDD quando è difficile prevedere il risultato del codice in prova?
Un esempio (reale) di codice con risultati difficili da prevedere:
Una funzione weightedTasksOnTimeche, data una quantità di lavoro svolto al giorno workPerDaynell'intervallo (0, 24], l'ora corrente initialTime> 0 e un elenco di attività taskArray; ognuna con un tempo per completare la proprietà time> 0, data di scadenza duee valore di importanza importance; restituisce un valore normalizzato nell'intervallo [0, 1] che rappresenta l'importanza delle attività che possono essere completate prima della duedata se ciascuna attività viene completata nell'ordine indicato da taskArray, a partire da initialTime.
L'algoritmo per implementare questa funzione è relativamente semplice: iterare le attività in taskArray. Per ogni attività, aggiungi timea initialTime. Se il nuovo tempo < due, aggiungi importancea un accumulatore. Il tempo viene regolato da inverso workPerDay. Prima di restituire l'accumulatore, dividere per somma delle importazioni di attività da normalizzare.
function weightedTasksOnTime(workPerDay, initialTime, taskArray) {
let simulatedTime = initialTime
let accumulator = 0;
for (task in taskArray) {
simulatedTime += task.time * (24 / workPerDay)
if (simulatedTime < task.due) {
accumulator += task.importance
}
}
return accumulator / totalImportance(taskArray)
}
Credo che il problema di cui sopra possa essere semplificato, pur mantenendo il suo nucleo, rimuovendo workPerDaye il requisito di normalizzazione, per dare:
function weightedTasksOnTime(initialTime, taskArray) {
let simulatedTime = initialTime
let accumulator = 0;
for (task in taskArray) {
simulatedTime += task.time
if (simulatedTime < task.due) {
accumulator += task.importance
}
}
return accumulator
}
Questa domanda affronta situazioni in cui il codice in esame non è una reimplementazione di un algoritmo esistente. Se il codice è una reimplementazione, ha intrinsecamente facili risultati da prevedere, poiché le implementazioni di fiducia esistenti dell'algoritmo fungono da naturale oracolo del test.