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