Je travaille fréquemment avec des programmes très numériques / mathématiques, où le résultat exact d'une fonction est difficile à prédire à l'avance.
En essayant d'appliquer TDD avec ce type de code, je trouve souvent que l'écriture du code sous test est beaucoup plus facile que l'écriture de tests unitaires pour ce code, car le seul moyen de connaître le résultat attendu est d'appliquer l'algorithme lui-même (que ce soit dans mon cas). tête, sur papier ou par ordinateur). Cela me semble erroné, car j’utilise efficacement le code testé pour vérifier mes tests unitaires, et non l’inverse.
Existe-t-il des techniques connues pour écrire des tests unitaires et appliquer TDD lorsque le résultat du code testé est difficile à prévoir?
Un exemple (réel) de code avec des résultats difficiles à prévoir:
Fonction weightedTasksOnTimequi, en fonction de la quantité de travail effectué par jour workPerDaydans la plage (0, 24], de l'heure actuelle initialTime> 0 et d'une liste de tâches taskArray, chacune avec un délai pour terminer la propriété time> 0, la date d'échéance dueet la valeur d'importance importance; renvoie une valeur normalisée dans l'intervalle [0, 1] représentant l'importance des tâches pouvant être terminées avant leur duedate si chaque tâche est complétée dans l'ordre indiqué en taskArraycommençant à initialTime.
L'algorithme pour implémenter cette fonction est relativement simple: itérer sur des tâches dans taskArray. Pour chaque tâche, ajoutez timeà initialTime. Si la nouvelle heure < due, ajoutez importanceà un accumulateur. Le temps est ajusté par workPerDay inverse. Avant de renvoyer l'accumulateur, divisez par la somme des importances de tâches à normaliser.
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)
}
Je crois que le problème ci-dessus peut être simplifié, tout en conservant son cœur, en supprimant workPerDayet en normalisant l'exigence, pour donner:
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
}
Cette question concerne les situations dans lesquelles le code testé n'est pas une nouvelle implémentation d'un algorithme existant. Si le code est une réimplémentation, il est intrinsèquement facile de prédire les résultats, car les implémentations fiables de l'algorithme agissent comme un oracle de test naturel.