Второй подход с использованием таких инструментов, как check или quickcheck , но ...
Дублирование деталей реализации
чувствует себя не так
Если вы дублируете, значит, вы делаете это неправильно. В своем коде вы пишете, что это за задача и как ее точно выполнять. В тесте вы даете несколько инвариантов о результате.
EDIT
Примечание по тестам на известные ответы (KAT)
Как и большинство обобщений, бывают ситуации, когда это не применимо. Одна большая область, где KAT доминируют над случайными векторами тестирования, - это криптография (например, блочные шифры), потому что не должно быть много видимых инвариантов за пределами того, что предписывает большинство систем типов (например: размер блока). Одно свойство для проверки будет decrypt(key,encrypt(key,msg)) == msg
.
Простая геометрия имеет несколько иную проблему в том, что ни один набор инвариантов не является действительно хорошей проверкой - вы можете сказать 0 < area(triangle) < triangle.width * triangle.height
, но это так же плохо. Я имею в виду, что вы должны писать тесты для немного более высокого уровня кода - что-то более сложное, что на самом деле имеет хорошие шансы измениться или ошибочно обмануть.
Ситуации для случайных тестовых векторов
Некоторые свойства кода, которые указывают на хорошее место для быстрой проверки свойств, включают
- детерминизм
- Нетривиальный
- очистить инварианты
Тривиальный пример использования конкатенации (объединение двух списков в серии для формирования одного нового списка):
Скажем, у меня есть функция concat(xs,ys) = xs ++ ys
. Что я могу проверить? Все, что я ожидаю, чтобы быть правдой! Длина? Да! Элементы? Да!
prop_len(xs,ys) = len(xs) + len(ys) = len(concat(xs,ys))
prop_elem(xs,ys) =
let cs = concat(xs,ys)
elem(head xs, cs) && elem(head ys, cs) && prop_elem(tail xs,ys) && prop_elem(xs,tail ys)
// Yes, I left out the error checking for empty list, sue me.
Получить дрейф?