Development

Тестируйте требуемое поведение, а не случайное

(В оригинале – Test for Required Behavior, not Incidental Behavior)

Общая проблема тестирования – предположить, что вам нужно тестировать точно то, что делает приложение. На первый взгляд это предположение звучит вполне здраво. Но если озвучить его немного по-другому, то проблема будет более заметной: проблема тестирования – привязать тесты к специфике реализации, когда эта специфика случайна и не относится к желаемой функциональности.

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

Предположение, что ложноположительное срабатывание указывает на реальную ошибку, может приводить к страху, неуверенности и беспокойству. Возрастает ощущение того, что программа ведет себя нестабильно. В случае переписывания теста программисты либо переделывают его так, чтобы он затрагивал желаемую функциональность (это правильно!) или же приспосабливают тест к новой реализации (а так делать не стоит!). Тесты должны быть точными, но при этом должны быть и аккуратными.

Например, сравнение вроде strcmp в С или String.compareTo в Java требует, чтобы результат был отрицательным, если левая часть меньше правой, положительным, если наоборот и нулевым, если обе части равны. Этот стиль сравнения используется множеством API, включая comparator для функции qsort в С и CompareTo в Comparable интерфейсе в Java. И хотя в реализациях очень часто используются значения +1 и -1 , считать, что эти значения являются требованием к реализации, будет ошибкой. Написание теста исходя из этого предположения приведет к тому, что ошибочное предположение материализуется.

Подобные вещи происходят с тестами, проверяющими количество пробелов, точное написание слов и другие аспекты форматирования, часто являющиеся случайными. Кроме случаев, когда вы пишете XML-генератор, предлагающий настраиваемое форматирование, количество пробелов не должно быть значимым для итогового результата. Точно также жесткая привязка к позициям элементов GUI снижает возможность дальнейшего изменения. Небольшое и незначимое изменение в реализации или форматировании в результате внезапно становится «убийцей» сборки.

Слишком специфические тесты часто являются проблемой при тестировании по принципу «белого ящика». В этом случае структура кода определяет необходимые тест-кейсы. Типичная ошибка при этом – что тестирование заключается в проверке того, что код делает именно то, что он делает. Такие тесты не добавляют ценности и лишь приводят к ложной уверенности в прогрессе и стабильности.

Чтобы быть эффективными, тесты должны проверять только контрактные обязательства, а не реализацию. Тестируемый юнит должен рассматриваться как «черный ящик», предоставляющий интерфейс в исполняемом виде. Поэтому старайтесь, чтобы тестируемое поведение было идентичным требуемому.

Автор оригинала – Kevlin Henney