- •4.9.1. Изменяемость
- •4.9.2. Классы операций
- •98 Глава 4
- •4.9.3. Полнота
- •100 Глава 4
- •4.9.5. Операции egual, similar и copy
- •102 Глава 4
- •104 Глава 4
- •5. Исключительные ситуации
- •108 Глава 5
- •110 Глава 5
- •6.2.1. Сигнализация об исключительных ситуациях
- •5.2.2. Обработка исключительных ситуаций
- •112 Глава 5
- •5.2.3. Предложение resignal
- •6.2.4. Необрабатываемые исключительные ситуации
- •114 Глава 5
- •6.2.3. Предложение resignal
- •5.2.4. Необрабатываемые исключительные ситуации
- •116 Глава 5
- •118 Глава 5
- •118 Глава 5
- •120 Глава 5
- •122 Глава 5
- •124 Глава 5
- •128 Глава 6
- •130 Глава 6
- •6.2.1. Реализация итераторов
- •6.2.2. Использование итераторов
- •132 Глава 6
- •134 Глава 6
- •136 Глава 6
- •138 Глава 6
- •140 Глава 7
- •142 Глава 7
- •7.2. Абстракция данных
- •144 Глава 7
- •146 Глава 7
- •148 Глава 7
- •150 Глава 7
- •7.4. Генераторы
- •162 Глава 7
- •154 Глава 7
- •156 Глава 7
- •162 Глава 8
- •164 Глава 8
- •166 Глава 8
- •168 Глава 8
- •170 Глава 9
- •172 Глава 9
- •174 Глава 9
- •176 Глава 9
- •9.1.3. Пример
- •178 Глава 9
- •180 Глава 9
- •182 Глава 9
- •184 Глава 9
- •186 Глава 9
- •188 Глава 9
- •190 Глава 9
- •192 Глава. 9
- •194 Глава 9
192 Глава. 9
^.Тестирование и отладка
Предположим, что в программе, вызывающей эту процедуру, перепутан порядок следования входных аргументов. В этом случае процедура in_range, вероятнее всего, возвратит значение false вне зависимости от того, присутствует ли е в массиве а или нет. Первый заметный симптом такого неправильного обращения может показаться не связанным с этим обращением. В худшем случае ошибка никогда не будет обнаружена и программа, вызывающая процедуру in_range, просто возвратит неправильный результат. Однако если в случае х > у процедура in_range выдаст сообщение об ошибке, то последняя будет обнаружена немедленно.
Аналогичные ошибки могут возникать при отсутствии полной проверки условных выражений. Например, предположим, что процедура receive передает в сообщении посланную по сети строку и для данного обращения к ней имеют смысл только значения «deliver» и «examine». Реализация
s := receive ( )
if s =^ "deliver" then % выполнить запрос на передачу elseif s = "examine" then % выполнить анализ else signal failure ("unexpected request:" fls) end
гораздо лучше приведенной ниже
s := receive ( ) if s == "deliver"
then % выполнить запрос на передачу else % выполнить анализ end
Если инвариант представления новый или был модифицирован, то он должен проверяться в начале каждой операции и перед возвращением. Для облегчения этой операции в кластер должна входить программа, выполняющая соответствующую проверку. Эта программа должна завершаться успешно, если инвариант представления удовлетворен, и выдавать сигнал ошибки — в противном случае.
Инварианты представления и требования служат двумя примерами утверждений о промежуточных стадиях вычислений. В гл. II мы рассмотрим еще несколько видов утверждений. Часто полезно создавать программы, проверяющие эти утверждения. Защитное программирование обычно предполагает дополнительные затраты машинного времени и рабочего времени программиста. Как правило, дополнительный труд программиста не является в данном случае принципиальным пунктом, поскольку защитное программирование почти всегда сокращает общий объем работы программиста над проектом. С увеличением времени работы часто приходится считаться. Для программ, у которых одним изтребо-
1.ваний является производительность, отдельные методы защитного ^программирования могут оказаться неприемлемыми. Если, например, аппаратная часть не регистрирует арифметическое переполнение, то программное выполнение этой операции может вдвое увеличить стоимость выполнения арифметических операций. В частности, процедура двоичного поиска не может позволить себе проверку на упорядоченность каждого входного массива.
Если имеется подозрение, что использовать защитное программирование в рабочей версии программы довольно дорого, то рекомендуется использовать его хотя бы на этапе создания программы. Удаление из текста программ, обнаруживающих ошибки, гораздо легче, чем вставка их в процессе отладки. Удаление из программы средств защиты должно быть тщательно продумано. Если это возможно, они должны быть оставлены в окончательной версии. Почти всегда очевидно, что когда программа попадет к пользователям, она еще будет содержать некоторые ошибки, а в процессе модификации к ним добавятся новые. Важно, чтобы эти ошибки могли быть обнаружены и исправлены максимально быстро. Фактическая экономическая стоимость необнаруженной ошибки в программе может превысить стоимость всех проверок на этапе отладки. В любом случае лучше сохранить все возможные «недорогие» проверки.
Заключение
В данной главе были рассмотрены различные вопросы тестирования и отладки. Тестирование представляет собой метод проверки корректности программы. Мы описали способ построения различных вариантов тестирования, основанный на методичном рассмотрении спецификации и реализации модуля. Тесты затем должны быть выполнены под управлением драйвера, который проверяет результаты для каждого из случаев. Драйвер либо сам генерирует входные данные, либо получает их из файла и либо проверяет результаты вычислений, либо сравнивает их с данными из другого файла. Если тестируется отдельный модуль, то модули, расположенные на нижнем уровне, должны быть заменены эмулирующими их заглушками. Позднее, на этапе интегральной проверки, заглушки заменяются реальными программами.
Тестирование позволяет обнаружить наличие ошибки. Отладка представляет собой процесс, понимания причины ошибки и последующего ее исправления. При отладке мы пытаемся сузить область проблемы, отыскивая более простые варианты тестов, которые выявляют ошибку, а затем просматриваем промежуточные величины, отыскивая участок программы, содержащий ошибку. После сбора различных свидетельств об ошибке мы формулируем гипотезы и пытаемся подтвердить их дальнейшим тестированием. 7 дисков b.i Гатэг Дж.
