Должен ли я написать тесты, которые напрямую отображают входные данные или динамически генерируют результат? - PullRequest
3 голосов
/ 18 января 2011

Старый программист, плохо знакомый с написанием тестовых случаев (позор мне, я знаю).

Мне кажется, что есть два способа написания тестовых случаев:

  1. Картафиксированные входы на фиксированные выходы и утверждают, что они соответствуют
  2. Отображение сгенерированных или фиксированных входов на динамические выходы и утверждают, что они соответствуют

# Static testing:
assert_equal "test".upcase, "TEST"

# Dynamic testing:
assert_equal person.full_name, "#{person.title} #{person.first_name} #{person.last_name}"

Конечно, естьплюсы и минусы каждого подхода.Дублирование деталей реализации кажется неправильным, но позволяет мне генерировать образцы данных и запускать на них тесты.Значения жесткого кодирования делают правильный вывод очень явным, но, похоже, не позволяют повторно использовать код.

Является ли первый способ традиционным написанием тестов?Вы смешиваете и подбираете подходы?Избегается ли последний метод по уважительной причине, о которой я не думал?

Ответы [ 2 ]

1 голос
/ 18 января 2011

Второй подход с использованием таких инструментов, как check или quickcheck , но ...

Дублирование деталей реализации чувствует себя не так

Если вы дублируете, значит, вы делаете это неправильно. В своем коде вы пишете, что это за задача и как ее точно выполнять. В тесте вы даете несколько инвариантов о результате.

EDIT

Примечание по тестам на известные ответы (KAT)

Как и большинство обобщений, бывают ситуации, когда это не применимо. Одна большая область, где KAT доминируют над случайными векторами тестирования, - это криптография (например, блочные шифры), потому что не должно быть много видимых инвариантов за пределами того, что предписывает большинство систем типов (например: размер блока). Одно свойство для проверки будет decrypt(key,encrypt(key,msg)) == msg.

Простая геометрия имеет несколько иную проблему в том, что ни один набор инвариантов не является действительно хорошей проверкой - вы можете сказать 0 < area(triangle) < triangle.width * triangle.height, но это так же плохо. Я имею в виду, что вы должны писать тесты для немного более высокого уровня кода - что-то более сложное, что на самом деле имеет хорошие шансы измениться или ошибочно обмануть.

Ситуации для случайных тестовых векторов Некоторые свойства кода, которые указывают на хорошее место для быстрой проверки свойств, включают

  1. детерминизм
  2. Нетривиальный
  3. очистить инварианты

Тривиальный пример использования конкатенации (объединение двух списков в серии для формирования одного нового списка):

Скажем, у меня есть функция 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.

Получить дрейф?

1 голос
/ 18 января 2011

Я обычно использую второй подход, так как у меня есть куча переменных, объявленных выше утверждений, которые я, возможно, захочу изменить однажды.Я думаю, вы должны спросить себя, каким образом становится понятнее, как реализовать вызов метода.Для меня это легко второй подход.Для юнит-тестов это обычно имеет смысл.Однако в приемочных испытаниях первый подход используется гораздо чаще.Совсем недавно мне пришлось проверить, что изображение, возвращаемое после вызова API, является правильным.Я мог бы попытаться построить изображение на основе данных, которые мне дали, или у меня могло бы быть эталонное изображение.Это означает, что приемочный тест еще не завершен до написания кода, и я должен продолжать проверять изображение вручную до тех пор, пока не завершится работа разработчика.Однако, как только изображение становится «правильным», у меня все еще есть что-то, чтобы остановить регрессию.Обычно я думаю, что вам решать, какой подход подходит для теста, который вы пишете.

...