Я часто працюю з дуже числовими / математичними програмами, де точний результат функції важко передбачити заздалегідь.
Намагаючись застосувати TDD з таким кодом, я часто вважаю, що писати код під тестом значно простіше, ніж писати одиничні тести для цього коду, тому що єдиний спосіб, який я знаю, щоб знайти очікуваний результат, - це застосувати сам алгоритм (чи в моєму головою, на папері або за комп’ютером). Це відчуває себе неправильно, оскільки я ефективно використовую тестований код для перевірки моїх тестових одиниць, а не навпаки.
Чи відомі методи написання одиничних тестів та застосування TDD, коли результат перевіреного коду важко передбачити?
(Реальний) приклад коду з важко передбачуваними результатами:
Функція, weightedTasksOnTime
яка, враховуючи кількість робіт, виконаних за день workPerDay
в діапазоні (0, 24], поточний час initialTime
> 0, і список завдань taskArray
; кожне з часом заповнити властивість time
> 0, термін due
і значення важливості importance
; повертається нормоване значення в діапазоні [0, 1], що представляє важливість завдань, які можна виконати до їх due
дати, якщо кожне завдання, якщо виконане в порядку, заданому taskArray
, починаючи з initialTime
.
Алгоритм реалізації цієї функції відносно простий: ітерайте над завданнями в taskArray
. Для кожного завдання додайте time
до initialTime
. Якщо новий час < due
, додайте importance
до акумулятора. Час регулюється за допомогою зворотного робочого дня. Перш ніж повернути акумулятор, розділіть їх на суму важливих завдань для нормалізації.
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)
}
Я вважаю, що вищезазначена проблема може бути спрощена, зберігаючи її суть, видаляючи workPerDay
та вимогу нормалізації, щоб:
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
}
Це питання стосується ситуацій, коли тестований код не є повторною реалізацією існуючого алгоритму. Якщо код є повторною реалізацією, він по суті має легко передбачити результати, тому що існуючі надійні реалізації алгоритму виступають як природний тестовий оракул.