Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
45
Добавлен:
23.03.2015
Размер:
884 Кб
Скачать

186 Глава 9

пирование и отладка

является простым и false в противном случае. При тестировании в качестве первого значения мы используем число 2 и наша про­грамма возвратит правильный ответ — false. Затем мы пробуем число 3 и программа возвратит неверный результат — false. Итак, имеется два результата, на основании которых мы попы­таемся сформулировать гипотезу. К одной из возможных и прият­ных для нас гипотез относится ситуация, при которой после первого теста нам каким-либо образом не удалось реинициализи-ровать программу. Это ведет к тому, что программа всегда рабо­тает правильно при первом проходе и всегда неправильно — при последующих. (При работе с языком CLU такая ошибка мало­вероятна.) Для проверки этой гипотезы мы можем проверить нашу программу с теми же аргументами, однако следует изменить порядок их следования, т. е. сначала мы подставим число 3, а за­тем — 2. Перед запуском тестов необходимо решить, какой ре­зультат подтвердит нашу гипотезу и какой — опровергнет.

1. Результаты, подтверждающие гипотезу (true, false).

2. Результаты, отвергающие гипотезу (false, true), (false,

alse), (true, true)

Пусть в процессе эксперимента программа возвратила сначала значение false, а затем true. Мы сразу же отбрасываем нашу пер­вую гипотезу и выдвигаем другую, например, что программа выполняется неправильно со всеми нечетными' простыми числами.

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

Например, предположим, что мы тестируем процедуру palin-drome, приведенную на рис. 9.2, и обнаруживаем, что выполнение ее со знаменитым палиндромом Наполеона «able was I ere I saw elba» приводит к ошибке. Это довольно длинный палиндром, поэтому желательно подобрать более короткий, также выдающий отрицательный результат. Мы начнем с того, что возьмем палин­дром, состоящий из одной буквы «г», расположенной в центре исходной фразы, а затем проверим, распознает ли его программа. Если программа не распознает палиндром из одной буквы, то можно предположить, что не распознаются все палиндромы с не­четным числом символов. Если палиндром «г» будет распознан, то мы можем затем попробовать палиндром «ere», исходя из гипо­тезы, что программа не работает со всеми палиндромами с нечет­ным числом символов, если это число больше единицы. Если

при случае с «ere» ошибка также не возникнет, то мы, вероятно, ожем попробовать «I ere 1». Предположим, что в этом случае Программа выполнится неправильно. Напрашиваются два пред-доложения: либо ошибка связана с символами пробела, либо 1 использованием букв верхнего регистра. Мы должны теперь Проверить это с кратчайшими палиндромами, например с «» и «1». 1 После того как мы найдем простое входное значение, вызы-1вающее ошибку, мы можем использовать ее для поиска места ^возникновения этой ошибки. Обычно нахождение входных данных, ввызывающих ошибку, является достаточным для определения ее .местоположения. Однако если это не так, то необходимо сузить .область поиска, просматривая для этого промежуточные резуль­таты.

В данном случае наша цель заключается в выделении частей программы, которые не относятся к возникшей проблеме, и после­дующем подробном анализе оставшихся частей. Мы делаем это при помощи трассировки программы, т. е. запуская ее и анализи­руя значения отдельных переменных в различных точках. Если программа состоит из нескольких модулей, то наша первая цель — обнаружить, какой модуль служит источником ошибки. Мы де­лаем это, анализируя все вызовы и возвраты из процедур. (Для итераторов анализируются значения в каждом проходе.) Для каждого вызова производится проверка правильности аргументов. Аргументы должны удовлетворять требованиям, указанным в предложении requires вызываемой процедуры, а также учиты­вать результаты предыдущих трассировок. Если аргументы не соответствуют требуемым, то ошибку следует искать в вызыва­ющем модуле. В противном случае мы должны выяснить, соответ­ствуют ли получаемые результаты указанным аргументам. Если это не так, то ошибка принадлежит вызываемой процедуре.

Локализация проблемы сведением ее к одной процедуре или циклу часто оказывается достаточной, поскольку мы можем обнаружить ошибку просмотром текста соответствующего модуля. Однако часто полезно бывает выделить в модуле только часть, содержащую ошибку. Для этого мы продолжаем проводить трас­сировку и анализ локальных переменных данного модуля. В этом случае необходимо обнаружить первое свидетельство неправиль­ного выполнения. В частности, важно проверить соответствие промежуточных результатов значениям, полученным до начала трассировки. Необходимо четко представлять себе, какими должны быть промежуточные результаты.

Рассмотрим неверно составленную реализацию процедуры palindrome:

palindrome = proc (s: string) returns (bool) low: int := I high int := string$size (s)

Соседние файлы в папке POSIBNIK