
- •1. Отладка программы
- •2. Локализация ошибок
- •3. Принципы отладки
- •4. Методы отладки
- •1. Трассировка и промежуточная печать
- •2. Метод индукции
- •3. Метод дедукции
- •4. Обратное движение по алгоритму
- •5. Тестирование
- •5. Средства отладки
- •6. Классификация ошибок
- •7. Советы отладчику
- •8. Тестирование
- •9. Проектирование тестов
- •10. Стратегии тестирования
- •Отладка в Delphi
|
Отла́дка — этап разработки компьютерной программы, на котором обнаруживают, локализуют и устраняют ошибки. Чтобы понять, где возникла ошибка, приходится:
узнавать текущие значения переменных;
выяснять, по какому пути выполнялась программа.
Существуют две взаимодополняющие технологии отладки.
Использование отладчиков — программ, которые включают в себя пользовательский интерфейс для пошагового выполнения программы: оператор за оператором, функция за функцией, с остановками на некоторых строках исходного кода или при достижении определённого условия.
Вывод текущего состояния программы с помощью расположенных в критических точках программы операторов вывода — на экран, принтер, громкоговоритель или в файл. Вывод отладочных сведений в файл называется журналированием.
Отладка и тестирование программ.
1. Отладка программы
Отладка, как мы уже говорили, бывает двух видов: Синтаксическая отладка. Синтаксические ошибки выявляет компилятор, поэтому исправлять их достаточно легко. Семантическая (смысловая) отладка. Ее время наступает тогда, когда синтаксических ошибок не осталось, но результаты программа выдает неверные. Здесь компилятор сам ничего выявить не сможет, хотя в среде программирования обычно существуют вспомогательные средства отладки, о которых мы еще поговорим. Отладка - это процесс локализации и исправления ошибок в программе.
Как бы тщательно мы ни писали, отладка почти всегда занимает больше времени, чем программирование.
2. Локализация ошибок
Локализация - это нахождение места ошибки в программе.
В процессе поиска ошибки мы обычно выполняем одни и те же действия: прогоняем программу и получаем результаты; сверяем результаты с эталонными и анализируем несоответствие; выявляем наличие ошибки, выдвигаем гипотезу о ее характере и месте в программе; проверяем текст программы, исправляем ошибку, если мы нашли ее правильно.
Способы обнаружения ошибки: Аналитический - имея достаточное представление о структуре программы, просматриваем ее текст вручную, без прогона. Экспериментальный - прогоняем программу, используя отладочную печать и средства трассировки, и анализируем результаты ее работы.
Оба способа по-своему удобны и обычно используются совместно.
3. Принципы отладки
Принципы локализации ошибок: Большинство ошибок обнаруживается вообще без запуска программы - просто внимательным просматриванием текста. Если отладка зашла в тупик и обнаружить ошибку не удается, лучше отложить программу. Когда глаз "замылен", эффективность работы упорно стремится к нулю. Чрезвычайно удобные вспомогательные средства - это отладочные механизмы среды разработки: трассировка, промежуточный контроль значений. Можно использовать даже дамп памяти, но такие радикальные действия нужны крайне редко. Экспериментирования типа "а что будет, если изменить плюс на минус" - нужно избегать всеми силами. Обычно это не дает результатов, а только больше запутывает процесс отладки, да еще и добавляет новые ошибки.
Принципы исправления ошибок еще больше похожи на законы Мерфи: Там, где найдена одна ошибка, возможно, есть и другие. Вероятность, что ошибка найдена правильно, никогда не равна ста процентам. Наша задача - найти саму ошибку, а не ее симптом. Это утверждение хочется пояснить. Если программа упорно выдает результат 0,1 вместо эталонного нуля, простым округлением вопрос не решить. Если результат получается отрицательным вместо эталонного положительного, бесполезно брать его по модулю - мы получим вместо решения задачи ерунду с подгонкой. Исправляя одну ошибку, очень легко внести в программу еще парочку. "Наведенные" ошибки - настоящий бич отладки. Исправление ошибок зачастую вынуждает нас возвращаться на этап составления программы. Это неприятно, но порой неизбежно.
4. Методы отладки
Силовые методы - Использование дампа (распечатки) памяти. Это интересно с познавательной точки зрения: можно досконально разобраться в машинных процессах. Иногда такой подход даже необходим - например, когда речь идет о выделении и высвобождении памяти под динамические переменные с использованием недокументированных возможностей языка. Однако, в большинстве случаев мы получаем огромное количество низкоуровневой информации, разбираться с которой - не пожелаешь и врагу, а результативность поиска - исчезающе низка. - Использование отладочной печати в тексте программы - произвольно и в большом количестве. Получать информацию о выполнении каждого оператора тоже небезынтересно. Но здесь мы снова сталкиваемся со слишком большими объемами информации. Кроме того, мы здорово захламляем программу добавочными операторами, получая малочитабельный текст, да еще рискуем внести десяток новых ошибок. - Использование автоматических средств отладки - трассировки с отслеживанием промежуточных значений переменых. Пожалуй, это самый распространенный способ отладки. Не нужно только забывать, что это только один из способов, и применять всегда и везде только его - часто невыгодно. Сложности возникают, когда приходится отслеживать слишком большие структуры данных или огромное их число. Еще проблематичнее трассировать проект, где выполнение каждой подпрограммы приводит к вызову пары десятков других. Но для небольших программ трассировки вполне достаточно.
С точки зрения "правильного" программирования силовые методы плохи тем, что не поощряют анализ задачи.
Суммируя свойства силовых методов, получаем практические советы: - использовать трассировку и отслеживание значений переменных для небольших проектов, отдельных подпрограмм; - использовать отладочную печать в небольших количества и "по делу"; - оставить дамп памяти на самый крайний случай.
Метод индукции - анализ программы от частного к общему. Просматриваем симптомы ошибки и определяем данные, которые имеют к ней хоть какое-то отношение. Затем, используя тесты, исключаем маловероятные гипотезы, пока не остается одна, которую мы пытаемся уточнить и доказать. Метод дедукции - от общего к частному. Выдвигаем гипотезу, которая может объяснить ошибку, пусть и не полностью. Затем при помощи тестов эта гипотеза проверяется и доказывается. Обратное движение по алгоритму. Отладка начинается там, где впервые встретился неправильный результат. Затем работа программы прослеживается (мысленно или при помощи тестов) в обратном порядке, пока не будет обнаружено место возможной ошибки. Метод тестирования.
Давайте рассмотрим процесс локализации ошибки на конкретном примере. Пусть дана небольшая программа, которая выдает значение максимального из трех введенных пользователем чисел.
var a, b, c: real; begin writeln('Программа находит значение максимального из трех введенных чисел'); write('Введите первое число '); readln(a); write('Введите второе число '); readln(b); write('Введите третье число '); readln(c); if (a>b)and(a>c) then writeln('Наибольшим оказалось первое число ',a:8:2) else if (b>a)and(<strong>a</strong>>c) then writeln('Наибольшим оказалось второе число ',b:8:2) else writeln('Наибольшим оказалось третье число ',<strong>b</strong>:8:2); end.
Обе выделенные ошибки можно обнаружить невооруженным глазом: первая явно допущена по невнимательности, вторая - из-за того, что скопированную строку не исправили.
Тестовые наборы данных должны учитывать все варианты решения, поэтому выберем следующие наборы чисел:
Данные Ожидаемый результат a=10; b=-4; c=1 max=a=10 a=-2; b=8; c=4 max=b=8 a=90; b=0; c=90.4 max=c=90.4
В результате выполнения программы мы, однако, получим следующие результаты: Для a=10; b=-4; c=1:
Наибольшим оказалось первое число 10.00
Для a=-2; b=8; c=4: < pre class=list>Наибольшим оказалось третье число 8.00Для a=90; b=0; c=90.4:
Наибольшим оказалось третье число 0.00
Вывод во втором и третьем случаях явно неверен. Будем разбираться.