Тесты должны быть точными
(В оригинале - Test Precisely and Concretely)
Важно тестировать желаемое, требуемое поведение кода, а не случайное поведение конкретной реализации. Однако это не должно быть оправданием для некорректно работающих тестов. Тесты должны быть точными.
Как обычно, сортировка – очень показательный пример. Реализация алгоритмов сортировки – не очень частая задача для программиста, однако сортировка – настолько простое понятие, что большинство людей верят, что они знают, чего от нее ожидать. Эта кажущаяся простота, однако, делает труднообнаруживаемыми неправильные предположения.
Если у программиста спросить: «А что же именно вы будете тестировать», наиболее частым ответом будет: «Результат сортировки – отсортированная последовательность элементов». И хотя это действительно так, это еще не все. Если попросить уточнить критерий, многие добавят, что результирующая последовательность должна быть той же длины, что и исходная. И это так, но этого все еще недостаточно. Возьмем для примера вот такую последовательность:
3 1 4 1 5 9
Следующая последовательность удовлетворяет критерию отсортированности и такой же длины, как и у входящей последовательности:
3 3 3 3 3 3
И хотя она и удовлетворяет критерию, очевидно, что она явно не то, что ожидается от алгоритма сортировки. Пример этот взят из реального кода (к счастью, проблема была «поймана» буквально перед самым выпуском), в котором из-за примитивной ошибки первый элемент входящей последовательности «размножался» на всю ее длину.
Полный критерий выглядит так: результат – отсортированная последовательность, при этом являющаяся перестановкой исходной последовательности. Это точно ограничивает требуемое поведение. Требование одинаковой длины отпадает как ненужное.
Но даже правильного вышеприведенного критерия еще недостаточно, чтобы написать хороший тест. Хороший тест должен быть легко читаемым. Он должен быть всеобъемлющим и при этом простым, чтобы было видно, правилен ли он. И если только у вас уже нет готового отлаженного кода, проверяющего, что последовательность отсортирована и что две последовательности являются перестановкой друг друга, то скорее всего, тестирующий код будет гораздо сложнее кода тестируемого. Как заметил Тони Хор (Tony Hoare):
Есть два варианта проектирования ПО: или сделать все настолько просто, что проблем не будет, или сделать все настолько сложно, что проблем не будет видно.
Использование конкретного случая устраняет излишнюю сложность и возможность для появления проблем. Например, для входной последовательности:
3 1 4 1 5 9
результат сортировки должен быть
1 1 3 4 5 9
Любой другой результат является неприемлемым.
Конкретные примеры помогают проиллюстрировать общее поведение простым и однозначным способом. Результат добавления элемента в пустое множество – не просто факт, что множество теперь не пустое, а то, что в множестве сейчас единственный элемент, и этот элемент совпадает с добавленным. Поскольку не пустое множество – это и два, и более элементов, что, однако, будет неправильным результатом. Результат добавления строки в таблицу не просто увеличение количества строк в таблице на один, а и то, что эту строку можно из таблицы извлечь по ее ключевому полю. И так далее.
При определении поведения тесты должны быть не только правильными, но и точными.
Автор оригинала - Kevlin Henney