Опишите вход и результат словами
Пусть функция принимает непустой список целых чисел и возвращает наибольшее значение. В этом описании уже есть ограничение: список не пуст. Можно также договориться, что исходный список не изменяется. Последнее важно, если вызывающий код использует прежний порядок элементов. Фраза работает с числами недостаточно точна: строки, дроби и специальные значения требуют отдельных решений. Чем яснее границы, тем проще подобрать примеры и понять, действительно ли найденная ошибка нарушает обещание функции.
Начальное значение должно соответствовать данным
В простом алгоритме текущий максимум берут из первого элемента, а затем сравнивают с оставшимися. Если вместо этого начать с нуля, список только из отрицательных чисел выявит ошибку. Например, для минус восьми, минус трёх и минус одиннадцати правильный ответ — минус три. Ноль вообще не входит в список. На положительных примерах неправильная версия может выглядеть рабочей. Поэтому тесты должны проверять границы предположений, а не только повторять удобный случай.
Пустой ввод требует отдельного решения
Для пустого списка нельзя выбрать первый элемент и нельзя назвать максимум среди отсутствующих значений. Контракт может запрещать такой вход и предусматривать понятную ошибку. Другой вариант — явно согласовать специальный результат или значение по умолчанию. Эти решения не взаимозаменяемы. Если вернуть ноль молча, вызывающий код может принять его за найденный максимум. Важно, чтобы отсутствие результата не смешивалось с обычным допустимым значением. Сначала выбирают поведение, затем реализуют его последовательно.
Проверяйте обещания, а не внутренние детали
Хорошая проверка сообщает, какой вход дан и какой результат ожидается. Для выбранного контракта нужны один элемент, повторяющиеся максимумы, все отрицательные числа и пустой ввод с ожидаемой ошибкой. Отдельно сравните список до и после вызова, если обещана неизменность. Необязательно требовать определённое число переменных или строго один способ перебора. Несколько реализаций могут выполнять одинаковый контракт. Но если меняются требования к памяти, времени или допустимым типам, эти ограничения тоже следует сформулировать явно.
Попробуйте на практике
Составьте проверяемый контракт и набор примеров для поиска максимума.
- Запишите вход: непустой список целых чисел; выход: его максимальное значение; дополнительное условие: порядок элементов сохраняется.
- Для списков из одного числа 4, чисел 2, 9, 9 и чисел минус 8, минус 3, минус 11 укажите ответы заранее.
- Опишите, что должно происходить при пустом списке; в этом упражнении выберите явную ошибку.
- Проследите алгоритм с начальным значением ноль и найдите пример, на котором он нарушает контракт.
- Исправьте рассуждение, начав с первого элемента, и проверьте, не осталось ли скрытого предположения о положительности чисел.
Как проверить результат. Ответы равны 4, 9 и минус 3. Пустой ввод не получает выдуманный максимум, а проверка сохранности исходного списка отделена от проверки возвращаемого значения.
Частые вопросы
Контракт нужен только большой библиотеке?
Нет. Даже небольшая функция становится понятнее, когда известны её вход, выход и поведение на границах. Масштаб описания можно выбирать по сложности задачи.
Несколько удачных проверок доказывают отсутствие всех ошибок?
Нет. Они подтверждают выбранные случаи. Их дополняют рассуждением об алгоритме и проверкой того, что все допустимые входы покрываются его логикой.
Самостоятельный разбор темы. Содержание конкретной обучающей программы здесь не представлено.