Иллюстрированный самоучитель по практике программирования

Тестируйте при написании кода

Следующим шагом будет проверка ввода около другой границы, когда массив почти заполнен, полностью заполнен и наконец переполнен, особенно если как раз в этот момент и встречается символ перевода строки. Мы не будем расписывать здесь все детали этих тестов; выполните их самостоятельно, – это очень хорошее упражнение. Задумавшись о всевозможных граничных условиях, нам придется решить, что делать в случае, если буфер заполнится до того, как во вводе встретится ' \п '; этот пробел в спецификации должен быть ликвидирован на ранней стадии написания программы.

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

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

Иллюстрированный самоучитель по практике программирования › Тестирование › Тестируйте при написании кода

Что будет делать эта функция, если n будет равно 0? Массив, не содержащий элементов, – вполне осмысленный элемент программы, а вот среднее значение его элементов не имеет никакого смысла. Должна ли функция позволять системе отлавливать деление на 0? Прерывать функцию? Сообщать об ошибке? Без предупреждения возвращать какое-нибудь нейтральное значение? А что если n вообще отрицательно, что абсолютно бессмысленно, но не невозможно? Как мы уже говорили в главе 4, нам представляется правильным в случае, если n меньше либо равно нулю, возвращать 0 в качестве среднего значения:

return n <= 0? 0.0

Но однозначно правильного ответа здесь не существует.

Имеется, правда, гарантированно неверное мнение – игнорировать проблему. В ноябре 1998 в журнале Scientific American был описан инцидент, произошедший на борту американского ракетного крейсера Yorktown. Член команды по ошибке вместо значимого числа ввел 0, что привело к ошибке деления на нуль; ошибка разрослась и в конце концов силовая установка корабля оказалась выведена из строя. Несколько часов Yorktown дрейфовал по воле волн – а все из-за того, что в программе не была осуществлена проверка диапазона вводимых значений.

Используйте утверждения.
В С и C++ существует возможность использования специального механизма утверждений (assertions) (в <assert.h>), который позволяет включать в программу проверку пред- и постусловий. Поскольку невыполненное утверждение прерывает работу программы, используют их, как правило, в ситуациях, когда сбой на самом деле не ожидается, а при его возникновении нет возможности продолжить работу нормально. Только что рассмотренный пример можно было бы дополнить утверждением, вставленным перед началом цикла:

assert(n > 0);

Если утверждение не выполнено, программа прерывается; сопровождается это выдачей стандартного сообщения:

Assertion failed: n > 0,
file avgtest.с, line 7
Abort(crash)

Утверждения особенно полезны при проверке свойств интерфейса, поскольку они привлекают внимание к несовместимости вызывающего и вызываемого блоков системы и зачастую помогают найти виновника этой несовместимости. Так, если наше утверждение, что n больше 0, не проходит при вызове функции, это сразу указывает на ошибку в вызывающей функции, а не в самой функции avg. Если интерфейс изменился, а внести соответствующие коррективы мы забыли, утверждения помогут выловить ошибку до того, как она приведет к возникновению серьезных проблем.

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.