Классификация ошибок
Успешное завершение процесса компиляции не означает, что в программе нет ошибок. Убедиться, что программа работает правильно можно только в процессе проверки ее работоспособности, который называется тестирование.
Обычно программа редко сразу начинает работать так, как надо, или работает правильно только на некотором ограниченном наборе исходных данных. Это свидетельствует о том, что в программе есть алгоритмические ошибки. Процесс поиска и устранение ошибок называется отладкой.
Ошибки, которые могут быть в программе, принято делить на три группы:
- синтаксические;
- ошибки времени выполнения;
- алгоритмические.
Синтаксические ошибки, их также называют ошибками времени компиляции (Compile-time error), наиболее легко устранимы. Их обнаруживает компилятор, а программисту остается только внести изменения в текст программы и выполнить повторную компиляцию.
Ошибки времени выполнения, в Delphi они называются исключениями (exception), тоже, как правило, легко устранимы. Они обычно проявляются уже при первых запусках программы и во время тестирования.
При возникновении ошибки в программе, запущенной из Delphi, среда разработки прерывает работу программы, о чем свидетельствует заключенное в скобки слово Stopped в заголовке главного окна Delphi, и на экране появляется диалоговое окно, которое содержит сообщение об ошибке и информа-
цию о типе (классе) ошибки. На рис. 13.1 приведен пример сообщения об ошибке, возникающей при попытке открыть несуществующий файл.
После возникновения ошибки программист может либо прервать выполнение программы, для этого надо из меню Run выбрать команду Program Reset, либо продолжить ее выполнение, например, по шагам (для этого из меню Run надо выбрать команду Step), наблюдая результат выполнения каждой инструкции.
Рис. 13.1. Сообщение об ошибке при запуске программы из Delphi
Если программа запушена из Windows, то при возникновении ошибки на экране также появляется сообщение об ошибке, но тип ошибки (исключения) в сообщении не указывается (рис. 13.2). После щелчка на кнопке ОК программа, в которой проявилась ошибка, продолжает (если сможет) работу.
Рис. 13.2. Сообщение об ошибке при запуске программы из Windows
С алгоритмическими ошибками дело обстоит иначе. Компиляция программы, в которой есть алгоритмическая ошибка, завершается успешно. При пробных запусках программа ведет себя нормально, однако при анализе результата выясняется, что он неверный. Для того чтобы устранить алгоритмическую ошибку, приходится анализировать алгоритм, вручную «прокручивать» его выполнение.
Помоги проекту! Расскажи друзьям об этом сайте
Лекция носит факультативный характер. Здесь мы рассматриваем виды допускаемых в программировании ошибок, способы тестирования и отладки программ, инструменты встроенного отладчика.
Цель лекции
Освоить работу с встроенным отладчиком, изучить категории ошибок, способы их обнаружения и устранения.
Тестирование и отладка программы
Чем больше опыта имеет программист, тем меньше ошибок в коде он совершает. Но, хотите верьте, хотите нет, даже самый опытный программист всё же допускает ошибки. И любая современная программ должна иметь собственные инструменты для отладки приложений, а также для своевременного обнаружения и исправления возможных ошибок. Программные ошибки на программистском сленге называют багами (англ. bug — жук), а программы отладки кода — дебаггерами (англ. debugger — отладчик). Lazarus, как современная приложений, имеет собственный встроенный отладчик, работу с которым мы разберем на этой лекции.
Ошибки, которые может допустить программист, условно делятся на три группы:
- Синтаксические
- Времени выполнения (run-time errors)
- Алгоритмические
Синтаксические ошибки
Синтаксические ошибки легче всего обнаружить и исправить — их обнаруживает , не давая скомпилировать и запустить программу. Причем устанавливает на ошибку, или после неё, а в окне сообщений выводит соответствующее сообщение, например, такое:
Рис.
27.1.
Найденная компилятором синтаксическая ошибка — нет объявления переменной i
Подобные ошибки могут возникнуть при неправильном написании директивы или имени функции (процедуры); при попытке обратиться к переменной или константе, которую не объявляли (
рис.
27.1); при попытке вызвать функцию (процедуру, переменную, константу) из модуля, который не был подключен в разделе ; при других аналогичных недосмотрах программиста.
Как уже говорилось, при нахождении подобной ошибки приостанавливает процесс компиляции, выводит сообщение о найденной ошибке и устанавливает на допущенную ошибку, или после неё. Программисту остается только внести исправления в и выполнить повторную компиляцию.
Ошибки времени выполнения
Ошибки времени выполнения (run-time errors) тоже, как правило, легко устранимы. Они обычно проявляются уже при первых запусках программы, или во . Если такую программу запустить из среды Lazarus, то она скомпилируется, но при попытке загрузки, или в момент совершения ошибки, приостановит свою работу, выведя на экран соответствующее сообщение. Например, такое:
Рис.
27.2.
Сообщение Lazarus об ошибке времени выполнения
Ошибка времени выполнения может возникнуть не только при загрузке программы, но и во время её работы. Например, если бы попытка чтения несуществующего файла была сделана не при загрузке программы, а при нажатии на кнопку, то бы нормально запустилась и работала, пока не нажмет на эту кнопку.
Если программу запустить из самой , при возникновении этой ошибки появится такое же сообщение. При этом если нажать «OK», даже может запуститься, но корректно работать все равно не будет.
Ошибки времени выполнения бывают не только явными, но и неявными, при которых продолжает свою работу, не выводя никаких сообщений, а программист даже не догадывается о наличии ошибки. Примером неявной ошибки может служить так называемая утечка памяти. Утечка памяти возникает в случаях, когда программист забывает освободить выделенную под . Например, мы объявляем переменную типа , и работаем с ней:
begin
MySL:= TStringList.Create;
MySL.Add(‘Новая строка’);
end;
В данном примере программист допустил типичную для начинающих ошибку — не освободил . Это не приведет к сбою или аварийному завершению программы, но в итоге можно бесполезно израсходовать очень много памяти. Конечно, эта будет освобождена после выгрузки программы (за этим следит ), но утечка памяти во программы тоже может привести к неприятным последствиям, потребляя все больше и больше ресурсов и излишне нагружая . В подобных случаях после работы с объектом программисту нужно не забывать освобождать :
Однако ошибки времени выполнения могут случиться и во время работы с объектом. Если есть такой риск, программист должен не забывать про возможность обработки исключительных ситуаций. В данном случае вышеприведенный код правильней будет оформить таким образом:
Алгоритмические ошибки
Если вы не допустили ни синтаксических ошибок, ни ошибок времени выполнения, скомпилировалась, запустилась и работает нормально, то это еще не означает, что в программе нет ошибок. Убедиться в этом можно только в процессе её тестирования.
Тестирование — процесс проверки работоспособности программы путем ввода в неё различных, даже намеренно ошибочных данных, и последующей контрольной проверке выводимого результата.
Если работает правильно с одними наборами исходных данных, и неправильно с другими, то это свидетельствует о наличии алгоритмической ошибки. Алгоритмические ошибки иногда называют логическими, обычно они связаны с неверной реализацией алгоритма программы: вместо «+» ошибочно поставили «-«, вместо «/» — «*», вместо деления значения на 0,01 разделили на 0,001 и т.п. Такие ошибки обычно не обнаруживаются во , нормально запускается, работает, а при анализе выводимого результата выясняется, что он неверный. При этом не укажет программисту на ошибку — чтобы найти и устранить её, приходится анализировать код, пошагово «прокручивать» его выполнение, следя за результатом. Такой процесс называется отладкой.
Отладка — процесс поиска и устранения ошибок, чаще алгоритмических. Хотя отладчик позволяет справиться и с ошибками времени выполнения, которые не обнаруживаются явно.
Выполнение программы с целью обнаружения ошибок называется тестированием. Локализация и исправление ошибок называется отладкой.
Отладка — это процесс локализации и исправления ошибок, обнаруженных при тестировании программного обеспечения. Локализацией называют процесс определения оператора программы, выполнение которого вызвало нарушение нормального вычислительного процесса. Для исправления ошибки необходимо определить ее причину, т. е. определить оператор или фрагмент, содержащие ошибку. Причины ошибок могут быть как очевидны, так и очень глубоко скрыты.
В целом сложность отладки обусловлена следующими причинами:
• требует от программиста глубоких знаний специфики управления используемыми техническими средствами, операционной системы, среды и языка программирования, реализуемых процессов, природы и специфики различных ошибок, методик отладки и соответствующих программных средств;
• психологически дискомфортна, так как необходимо искать собственные ошибки и, как правило, в условиях ограниченного времени;
• возможно взаимовлияние ошибок в разных частях программы, например, за счет затирания области памяти одного модуля другим из-за ошибок адресации;
• отсутствуют четко сформулированные методики отладки.
Синтаксические ошибки. Синтаксические ошибки относят к группе самых простых, так как синтаксис языка, как правило, строго формализован, и ошибки сопровождаются развернутым комментарием с указанием ее местоположения. Определение причин таких ошибок, как правило, труда не составляет, и даже при нечетком знании правил языка за несколько прогонов удается удалить все ошибки данного типа.
Следует иметь в виду, что чем лучше формализованы правила синтаксиса языка, тем больше ошибок из общего количества может обнаружить компилятор и соответственно меньше ошибок будет обнаруживаться на следующих этапах. В связи с этим говорят о языках программирования с защищенным синтаксисом и с незащищенным синтаксисом. К первым, безусловно, можно отнести Pascal, имеющий очень простой и четко определенный синтаксис, хорошо проверяемый при компиляции программы, ко вторым — Си со всеми его модификациями. Чего стоит хотя бы возможность выполнения присваивания в условном операторе в Си, например:
if (с=п) х-0; /* в данном случае не проверятся равенство с и n, а выполняется присваивание с значения п, после чего результат операции сравнивается с нулем, если программист хотел выполнить не присваивание, а сравнение, то эта ошибка будет обнаружена только на этапе выполнения при получении результатов, отличающихся от ожидаемых*/
Ошибки компоновки. Ошибки компоновки, как следует из названия, связаны с проблемами, обнаруженными при разрешении внешних ссылок. Например, предусмотрено обращение к подпрограмме другого модуля, а при объединении модулей данная подпрограмма не найдена или не стыкуются списки параметров. В большинстве случаев ошибки такого рода также удается быстро локализовать и устранить.
Ошибки выполнения. К самой непредсказуемой группе относятся ошибки выполнения. Прежде всего они могут иметь разную природу и соответственно по-разному проявляться. Часть ошибок обнаруживается и документируется операционной системой. Выделяют четыре способа проявления таких ошибок:
• появление сообщения об ошибке, зафиксированной схемами контроля выполнения машинных команд, например переполнении разрядной сетки, ситуации «деление на ноль», нарушении адресации и т. п.;
• появление сообщения об ошибке, обнаруженной операционной системой, например нарушении защиты памяти, попытке записи на устройства, защищенные от записи, отсутствии файла с заданным именем и т. п.;
• «зависание» компьютера как простое, когда удается завершить программу без перезагрузки операционной системы, так и «тяжелое», когда для продолжения работы необходима перезагрузка;
• несовпадение полученных результатов с ожидаемыми.
Примечание. Отметим, что если ошибки этапа выполнения обнаруживает пользователь, то в двух первых случаях, получив соответствующее сообщение, пользователь в зависимости от своего характера, степени необходимости и опыта работы за компьютером, либо попробует понять, что произошло, ища свою вину, либо обратится за помощью, либо постарается никогда больше не иметь дела с этим продуктом. При «зависании» компьютера пользователь может даже не сразу понять, что происходит что-то не то, хотя его печальный опыт и заставляет волноваться каждый раз, когда компьютер не выдает быстрой реакции на введенную команду, что также целесообразно иметь в виду. Также опасны могут быть ситуации, при которых пользователь получает неправильные результаты и использует их в своей работе.
Причины ошибок выполнения очень разнообразны, а потому и локализация может оказаться крайне сложной. Все возможные причины ошибок можно разделить на следующие группы:
• неверное определение исходных данных,
• логические ошибки,
• накопление погрешностей результатов вычислений (рис. 11.2).
Неверное определение исходных данных происходит, если возникают любые ошибки при выполнении операций ввода-вывода: ошибки передачи, ошибки преобразования, ошибки перезаписи и ошибки данных. Причем использование специальных технических средств и программирование с защитой от ошибок позволяет обнаружить и предотвратить только часть этих ошибок, о чем, безусловно, не следует забывать.
Рис. 11.2. Классификация ошибок этапа выполнения по возможным причинам
Логические ошибки имеют разную природу. Так они могут следовать из ошибок, допущенных при проектировании, например при выборе методов, разработке алгоритмов или определении структуры классов, а могут быть непосредственно внесены при кодировании модуля. К последней группе относят:
• ошибки некорректного использования переменных, например, неудачный выбор типов данных, использование переменных до их инициализации, использование индексов, выходящих за границы определения массивов, нарушения соответствия типов данных при использовании явного или неявного переопределения типа данных, расположенных в памяти при использовании нетипизированных переменных, открытых массивов, объединений, динамической памяти, адресной арифметики и т. п.;
• ошибки вычислений, например, некорректные вычисления над неарифметическими переменными, некорректное использование целочисленной арифметики, некорректное преобразование типов данных в процессе вычислений, ошибки, связанные с незнанием приоритетов выполнения операций для арифметических и логических выражений, и т. п.;
• ошибки межмодульного интерфейса, например, игнорирование системных соглашений, нарушение типов и последовательности при передаче параметров, несоблюдение единства единиц измерения формальных и фактических параметров, нарушение области действия локальных и глобальных переменных;
• другие ошибки кодирования, например, неправильная реализация логики программы при кодировании, игнорирование особенностей или ограничений конкретного языка программирования.
Накопление погрешностей результатов числовых вычислений возникает, например, при некорректном отбрасывании дробных цифр чисел, некорректном использовании приближенных методов вычислений, игнорировании ограничения разрядной сетки представления вещественных чисел в ЭВМ и т. п.
Все указанные выше причины возникновения ошибок следует иметь в виду в процессе отладки. Кроме того, сложность отладки увеличивается также вследствие влияния следующих факторов:
• опосредованного проявления ошибок;
• возможности взаимовлияния ошибок;
• возможности получения внешне одинаковых проявлений разных ошибок;
• отсутствия повторяемости проявлений некоторых ошибок от запуска к запуску — так называемые стохастические ошибки;
• возможности устранения внешних проявлений ошибок в исследуемой ситуации при внесении некоторых изменений в программу, например, при включении в программу диагностических фрагментов может аннулироваться или измениться внешнее проявление ошибок;
• написания отдельных частей программы разными программистами.
Классификация ошибок и тестов
Каждая организация, разрабатывающая ПО общесистемного назначения, сталкивается с проблемами нахождения ошибок. Поэтому приходится классифицировать типы обнаруживаемых ошибок и определять свое отношение к устранению этих ошибок.
На основе многолетней деятельности в области создания ПО разные фирмы создали свою классификацию ошибок, основанную на выявлении причин их появления в процессе разработки, в функциях и в области функциональной деятельности ПО.
Известно много различных подходов к классификации ошибок, рассмотрим некоторые из них.
Схема классификации не зависит от продукта, организации разработки и может применяться ко всем стадиям разработки ПО разного назначения. табл. 7.1 дает список ошибок согласно данной классификации. Используя эту таблицу, разработчик имеет возможность идентифицировать не только типы ошибок, но и места, где пропущены или совершены ошибки. Предусмотрены ситуации, когда найдена неинициализированная переменная или инициализированной переменной присвоено неправильное значение.
Ортогональность схемы классификации заключается в том, что любой ее термин принадлежит только одной категории.
Другими словами, прослеживаемая ошибка в системе должна находиться в одном из классов, что дает возможность разным разработчикам классифицировать ошибки одинаковым способом.
Это соотношение — типичное для многих фирм, производящих ПО, имеет некоторые отклонения.
Исследования фирм IBM показали, чем позже обнаруживается ошибка в программе, тем дороже обходится ее исправление, эта зависимость близка к экспоненциальной. Так военновоздушные силы США оценили стоимость разработки одной инструкции в 75 долларов, а ее стоимость сопровождения составляет около 4000 долларов.
Рис.
7.2.
Процентное соотношение ошибок при разработке ПО
Определение теста.Для проверки правильности программ специально разрабатываются тесты и тестовые данные. Под тестом понимается некоторая программа, предназначенная для проверки работоспособности другой программы и обнаружения в ней ошибочных ситуаций. Тестовую проверку можно провести также путем введения в проверяемую программу , которые будут сигнализировать о ходе ее выполнения и получения результатов.
Создаются тесты, проверяющие:
- полноту функций;
- согласованность интерфейсов;
- корректность выполнения функций и правильность функционирования системы в заданных условиях;- надежность выполнения системы;
- защиту от сбоев аппаратуры и не выявленных ошибок и др.
Тестовые данные готовятся как для проверки отдельных программных элементов, так и для групп программ или комплексов на разных стадиях процесса разработки. На рис. 7.3. приведена классификация тестов проверки по объектам тестирования на основных этапах разработки.
Многие типы тестов готовятся заказчиком для проверки работы программной системы. Структура и содержание тестов зависят от вида тестируемого элемента, которым может быть модуль, компонент, группа компонентов, подсистема или система. Некоторые тесты зависят от цели и необходимости знать: работает ли система в соответствии с ее проектом, удовлетворены ли требования и участвует ли заказчик в проверке работы тестов и т.п.
В зависимости от задач, которые ставятся перед тестированием программ, составляются тесты проверки промежуточных результатов проектирования элементов на этапах ЖЦ, а также создаются тесты испытаний окончательного кода системы.
Тесты интегрированной системы.Тесты для проверки отдельных элементов системы и тесты интегрированной системы имеют общие и отличительные черты. Так, на рис. 7.4 в качестве примера приведена схема интеграции готовых оттестированных элементов. В ней заданы связи между разными уровнями тестирования интегрируемой ПС.
Рис.
7.4.
Интегрированное тестирование компонент
Рассмотрим этот процесс более подробно. Каждый компонент этой схемы тестируется отдельно от других компонентов с помощью тестов, включающих наборы данных и сценарии, составленные в соответствии с их типами и функциями, специфицированные в проекте системы. Тестирование проводится в контрольной операционной среде на предопределенном множестве тестовых данных и операциях, производимых над ними.
Тесты обеспечивают проверку внутренней структуры, логики и граничных условий выполнения для каждого компонента.
При этом могут возникать ошибки, в случае неправильного задания параметров в операторах вызова или при вычислениях процедур или функций. Возникающие ошибки в связях устраняются, а затем повторно проверяется связь с компонентом F в виде троек: компонентинтерфейскомпонент.Следующим шагом тестирования комплексной системы является проверка функционирования системы с помощью тестов проверки функций и требований к ним. После проверки системы на функциональных тестах происходит проверка на исполнительных и испытательных тестах, подготовленных согласно требованиям к ПО, аппаратуре и выполняемым функциям. Испытательному тесту предшествует верификация и валидация ПО.
Тест испытаний системы в соответствии с требованиями заказчика проверяется в реальной среде, в которой система будет в дальнейшем функционировать.
Лекция посвящена описанию вопросов, касающихся отладки приложений и работы с ошибками.
Ошибки при создании программы
Можно выделить два типа ошибок, с которыми сталкивается программист. Во-первых — это ошибки, которые сопровождают создание программ, а во вторых — ошибки времени выполнения.
Если вы неправильно введете оператор или , если забудете указать часть выражения — ошибка сразу же будет заметна в редакторе. Такие ошибки относятся к . Также на этапе разработки можно обнаружить и устранить . Они связаны с неправильными формулами расчета показателей, неверным использованием переменных и т.д.
Приведем несколько примеров .
А вот — .
- Неправильное использование операторов. Например, вместо знака обычного деления вы случайно использовали знак целочисленного деления.
- Расчет какого-либо показателя по неправильной формуле. Например, если неточно расставить скобки в каком-либо выражении — это приведет к ошибке, хотя внешне все может выглядеть правильным.
- Неправильное использование функций — как встроенных, так и пользовательских. Например, используя функцию для получения строкового представления числа, вы не учли, что для положительных чисел эта функция добавляет в начало строки пробел. Далее вы попытались узнать первую цифру числа, вырезав первый символ полученной строки. Естественно, никакой цифры в этом случае не получится — лишь знак пробела для положительных или «минус» для отрицательных чисел.
- Неправильное использование переменных. Например, вы используете два для обработки двумерного массива. Одна из цикловых переменных имеет имя , вторая — . Они довольно сильно похожи внешне, их можно случайно перепутать при указании индексов массива. К тому же, обрабатывая массив в цикле довольно легко перепутать место каждой из переменных при указании . Использование понятных имен переменных (например — или для хранения возраста и т.д.) позволяет эффективно бороться с такими ошибками.
- Случайное использование «новых» переменных. Например, вы предложили пользователю ввести некое значение и записали его в переменную , а использовав эту переменную в выражении, напечатали не , а . Внешне они похожи, но, присмотревшись, вы можете обнаружить, что имена разные. Еще сложней искать ошибки в латинских именах переменных, в которые «вкрались» русские буквы. Разницу между и вы не увидите, но это — разные переменные — в конце второй вместо латинской использована русская . Эффективно бороться с такими ошибками можно, если задать в редакторе опцию обязательного объявления переменных ( ). При появлении необъявленной переменной редактор даст знать об этом.
- Неправильное использование оператора сравнения. Например, это может быть оператор, который сравнивает некие величины не так, как вы предполагали — вместо знака вы случайно использовали или, редактируя сравнение (скажем, скопировав похожий оператор сравнения из другого места программы для ускорения работы), поменяли местами сравниваемые переменные или выражения, не поменяв знака и т.д.
Ошибки логики можно найти лишь тщательно проверив и протестировав программу. Чтобы облегчить работу с кодом программы, рекомендуется снабжать ее комментариями. Вовсе необязательно комментировать каждую строчку, достаточно выделить крупные функциональные блоки.
Ошибки при выполнении программы
Такие ошибки называют еще ошибками времени выполнения. Происходят они, как правило, при неправильном вводе данных пользователем, при возникновении обстоятельств, делающих дальнейшую нормальную работу программы невозможной. Например, ошибку вызовет попытка использовать текстовые данные в арифметическом выражении, попытка сохранения файла в несуществующей директории, на ноль и т.д.
Ошибки времени выполнения возникают в нормально работающих программах, которые прошли проверку на синтаксическую и логическую правильность. С этими ошибками можно бороться используя один из двух методов. Первый — разработка программы таким образом, чтобы не допустить этих ошибок, создание программных конструкций, которые предотвращают возникновение ошибок. Второе — перехват ошибок и их обработка.
Давайте, для начала, рассмотрим способы поиска ошибок в процессе создания программ
Тестирование программ и поиск ошибок
, как уже было сказано, выявляются обычно на очень раннем этапе — сразу после набора текста в редакторе. А вот для поиска полезно протестировать программу.
Для начала протестируйте вашу программу в обычном режиме работы. Например, если вы предлагаете ввести пользователю число — введите сами число и проверьте результаты работы. Если действия программы будут различаться в зависимости от введенных данных — попытайтесь перебрать все варианты этих данных — так, чтобы проверить все ветви программы.
Если обычные проверки закончились успешно — можно считать, что ваша корректно работает, не имеет и .
После этого можно усложнить режим тестирования, чтобы как можно более полно сымитировать действия пользователя программы и посмотреть на ее поведение. Еще лучше — попытайтесь целенаправленно вызвать ошибку. Гораздо лучше, когда даст сбой на вашем рабочем столе, и вы сможете оперативно устранить этот сбой, чем ждать, когда то же самое произойдет у другого пользователя.
Для проверки программы в реальных условиях попробуйте провести следующие эксперименты.
- Если программа запрашивает число — введите какое-нибудь слово, очень большое число, ноль, отрицательное число, оставьте поле ввода пустым, введите дробное число. Если вы не предусмотрели никаких специальных мер по обработке ошибок, при выполнении подобных операций вы почти гарантированно встретитесь с проблемами.
- Попытайтесь запустить программу, открыв несколько окон с документами.
- Попытайтесь прервать работу программы, а потом снова возобновить ее. Если в вашей программе есть участки, в течение выполнения которых нельзя допускать прерывания работы программы пользователем — вам следует подумать о том, чтобы запретить прерывание работы программы на этих участках.
- Попытайтесь использовать вашу программу в более старой версии Microsoft Office, в нерусифицированной версии. Обратите внимание, например, на различия расширений имен файлов в Office 2007 и более старых версиях, на различия в объектных моделях. В общем случае программы из более старых версий Office будут работать в Office 2007, однако если они используют какие-то специфические особенности Office — такие программы нуждаются в проверке и обновлении. В то же время, макросы для Office 2007, использующие новые объектные модели, могут не работать или работать неправильно в старых версиях.
- Попытайтесь поработать с вашей программой на чужом ПК. Вполне возможно, что при таком эксперименте вы столкнетесь с ошибкой. Например, вы программно работаете с файлами на вашем рабочем ПК — если эти файлы отсутствуют на ПК другого пользователя или находятся в других директориях, или тех директорий, которые нужны вашей программе, нет на ПК другого пользователя — вы столкнетесь с ошибкой.
- Во время работы программы сделайте что-нибудь необычное. Как правило, от пользователей можно ожидать любых странных на первый взгляд действий. Если вы тестируете программу для MS Word, которая правит текст или занимается автоматическим созданием текста, попробуйте во время ее работы переключаться между документами, читать документ, вносить в него правки, выделять произвольные участки текста. То же самое касается MS Excel — во время работы программы попробуйте переключаться между открытыми книгами, между листами, выделять ячейки, попробуйте запустить программу, делая различные листы активными, открыв несколько книг. Результаты такого тестирования могут быть совершенно непредсказуемыми. Проанализировав их, вы можете прити к выводу, что, например, на время выполнения программы нужно скрывать или блокировать документ, пользоваться альтернативными методами работы с документом. Яркий пример — объект в MS Word, который чувствителен к смене выделения в процессе работы, и объект , который может работать совсем без создания выделения в тексте.
- Если ваша программа использует файлы, находящиеся в локальной сети, отключите сеть во время работы программы. Проверьте ее реакцию. То же самое можно сделать, если ваша программа работает с принтером — проверьте ее реакцию на выключенный принтер, на принтер, в котором нет бумаги.
- Наконец, представьте, что вы — пользователь программы и просто поработайте с ней. А еще лучше — попросите потенциального пользователя немного «пообщаться» с вашей программой. Этот способ позволяет протестировать программу в условиях, максимально приближенных к реальным.
Возможно, вам покажется, что такая проверка не нужна вашей программе. Если вы пишете небольшой для собственного использования, скорее всего, так оно и есть. Но стоит вашему проекту хоть немного вырасти, методы поиска и устранения ошибок могут оказаться очень кстати.
Если вы встретитесь с ошибками и затрудняетесь определить, где именно они происходят — попробуйте выполнить программу в пошаговом режиме, используйте встроенные в редактор средства для .
Отладка программ в редакторе VBA
Основной метод отладки — это пошаговое исполнение программы с использованием точек останова ().
Чтобы создать в программе точку останова, достаточно щелкнуть мышью в редакторе на серой панели напротив команды, на которой нужно остановить выполнение программы. Там появится большая красная точка (рис. 8.1.) — здесь будет остановлена в процессе выполнения. Строка будет подсвечена красным цветом.
Рис.
8.1.
Точка останова в программе
Следует понимать, что строка, подсвеченная при остановке программы еще не выполнялась — редактор указывает на нее, как бы говоря «Эта строка будет выполнена следующей».
Таких точек останова можно установить столько, сколько нужно — на тех строках программы, где вы подозреваете возникновение ошибки. Чтобы убрать точку останова, щелкните по ней мышью.
Установить точку останова в строку можно, выделив строку и выбрав команду Debug o Toggle Breakpoint ( o Установить точку останова). Для удаления всех точек останова из программы можно воспользоваться командой Debug o Clear All Breakpoints ( o Очистить точки останова).
Вместо точек останова, расставленных мышью или из , можно использовать оператор . Он останавливает работу программы и переводит ее в режим .
Так же режим можно включить, нажав во время работы программы комбинацию клавиш + Pause Break и нажав в появившемся окне кнопку . Текущая строка будет выделена желтым цветом, напротив нее будет установлена желтая стрелочка. Однако такой способ обычно не позволяет точно «попасть» в то программы, где находится предполагаемая ошибка (рис. 8.2.).
Рис.
8.2.
Программа, остановленная во время выполнения
Чтобы запущенная останавливалась на каждой строке, можно запустить ее в режиме командой Debug o Step Into ( o Пошаговое ). Того же эффекта можно достичь, нажав клавишу на клавиатуре.
Когда остановлена, вы можете выполнить следующие действия
- Просмотреть значения переменных, наведя на них указатель мыши. Например, на рис. 8.3. вы видите всплывающее окно, которое содержит значение переменной.Рис.
8.3.
Значение переменной во всплывающем окне - Продолжить выполнение программы в режиме Step Into — выбрав соответствующую команду меню или нажав клавишу F8.
- Отредактировать программу.
- Остановить выполнение программы командой Run o Reset (Запустить o Перезагрузка) или кнопкой на панели инструментов
- Воспользоваться другими средствами — окнами Immediate, Locals, Watch.
Помимо режима Step Into существуют следующие режимы отладки, доступные в Debug.
- Step Over (Перейти на следующую строку). Эта команда полезна при , содержащей вызовы уже отлаженных процедур. В режиме Step Over отладчик не входит в процедуру, выполняя ее без , после чего переходит на следующую строку. Например, вы выполняете программу в режиме Step Into и при очередной остановке видите, что подсвеченная строка содержит вызов процедуры, которую отлаживать не нужно. Вы выбираете команду Step Over, процедура выполняется без остановок на каждой ее строке, после чего следующая остановка происходит на строке вашей программы, которая идет за вызовом процедуры.
- Step Out (Выполнить процедуру) — эта команда позволяет выполнить текущую процедуру (например, вызванную из кода основной программы при обычной ) без остановки в каждой строке. Следующая остановка будет сделана на строке, которая следует за вызовом процедуры в основном тексте программы.
- Run To Cursor (Выполнить до курсора) — выполняет программу до позиции, на которой установлен курсор. Аналогично установке одиночной точки останова.
Помимо точек останова существуют и другие средства . Они полезны при проверке значений переменных (ведь если переменных достаточно много — проверка их значений в коде программы может превратиться в утомительное и непродуктивное занятие), свойств объектов, которые могут вызвать ошибки и в других случаях.
Ошибки в программировании – дело обычное, хоть и неприятное. В данной статье будет рассказано о том, какими бывают ошибки (баги), а также что собой представляют исключения.
Определение
Ошибка в программировании (или так называемый баг) – это ситуация у разработчиков, при которой определенный код вследствие обработки выдает неверный результат. Причин данному явлению множество: неисправность компилятора, сбои интерфейса, неточности и нарушения в программном коде.
Баги обнаруживаются чаще всего в момент отладки или бета-тестирования. Реже – после итогового релиза готовой программы. Вот несколько вариантов багов:
- Появляется сообщение об ошибке, но приложение продолжает функционировать.
- ПО вылетает или зависает. Никаких предупреждений или предпосылок этому не было. Процедура осуществляется неожиданно для пользователя. Возможен вариант, при котором контент перезапускается самостоятельно и непредсказуемо.
- Одно из событий, описанных ранее, сопровождается отправкой отчетов разработчикам.
Ошибки в программах могут привести соответствующее приложение в негодность, а также к непредсказуемым алгоритмам функционирования. Желательно обнаруживать баги на этапе ранней разработки или тестирования. Лишь в этом случае программист сможет оперативно и относительно недорого внести необходимые изменения в код для отладки ПО.
История происхождения термина
Баг – слово, которое используется разработчиками в качестве сленга. Оно произошло от слова «bug» – «жук». Точно неизвестно, откуда в программировании и IT возник соответствующий термин. Существуют две теории:
- 9 сентября 1945 года ученые из Гарварда тестировали очередную вычислительную машину. Она называлась Mark II Aiken Relay Calculator. Устройство начало работать с ошибками. Когда его разобрали, то ученые заметили мотылька, застрявшего между реле. Тогда некая Грейс Хоппер назвала произошедший сбой упомянутым термином.
- Слово «баг» появилось задолго до появления Mark II. Термин использовался Томасом Эдисоном и указывал на мелкие недочеты и трудности. Во время Второй Мировой войны «bugs» называли проблемы с радарной электроникой.
Второй вариант кажется более реалистичным. Это факт, который подтвержден документально. Со временем научились различать различные типы багов в IT. Далее они будут рассмотрены более подробно.
Как классифицируют
Ошибки работы программ разделяются по разным факторам. Классификация у рядовых пользователей и разработчиков различается. То, что для первых – «просто программа вылетела» или «глючит», для вторых – огромная головная боль. Но существует и общепринятая классификация ошибок. Пример – по критичности:
- Серьезные неполадки. Это нарушения работоспособности приложения, которые могут приводить к непредвиденным крупным изменениям.
- Незначительные ошибки в программах. Чаще всего не оказывают серьезного воздействия на функциональность ПО.
Последний вариант требует особого внимания со стороны программистов. Их стараются обнаружить и устранить в первую очередь. Критические ошибки могут отложить релиз исходной программы на неопределенный срок.
Также существуют различные виды сбоев в плане частоты проявления: постоянные и «разовые». Вторые встречаются редко, чаще – при определенных настройках и действиях со стороны пользователя. Первые появляются независимо от используемой платформы и выполненных клиентом манипуляций.
Иногда может получиться так, что ошибка возникает только на устройстве конкретного пользователя. В данном случае устранение неполадки требует индивидуального подхода. Иногда – полной замены компьютера. Связано это с тем, что никто не будет редактировать исходный код, когда он «глючит» только у одного пользователя.
Виды
Существуют различные типы ошибок в программах в зависимости от типовых условий использования приложений. Пример – сбои, которые возникают при возрастании нагрузки на оперативную память или центральный процессор устройства. Есть баги граничных условий, сбоя идентификаторов, несовместимости с архитектурой процессора (наиболее распространенная проблема на мобильных устройствах).
Разработчики выделяют следующие типы ошибок по уровню сложности:
- «Борбаг» – «стабильная» неполадка. Она легко обнаруживается на этапе разработки и компилирования. Иногда – во время тестирования наработкой исходной программы.
- «Гейзенбаг» – баги с поддержкой изменения свойств, включая зависимость от среды, в которой было запущено приложение. Сюда относят периодические неполадки в программах. Они могут исчезать на некоторое время, но через какой-то промежуток вновь дают о себе знать.
- «Мандельбаг» – непредвиденные ошибки. Обладают энтропийным поведением. Предсказать, к чему они приведут, практически невозможно.
- «Шрединбаг» – критические неполадки. Приводят к тому, что злоумышленники могут взломать программу. Данный тип ошибок обнаружить достаточно трудно, потому что они никак себя не проявляют.
Также есть классификация «по критичности». Тут всего два варианта – warning («варнинги») и критические весомые сбои. Первые сопровождаются характерными сообщениями и отчетами для разработчиков. Они не представляют серьезной опасности для работоспособности приложения. При компилировании такие сбои легко исправляются. В отдельных случаях компилятор справляется с этой задачей самостоятельно. А вот критические весомые сбои говорят сами за себя. Они приводят к серьезным нарушениям ПО. Исправляются обычно путем проработки логики и значительных изменений программного кода.
Типы багов
Ошибки в программах бывают:
- логическими;
- синтаксическими;
- взаимодействия;
- компиляционные;
- ресурсные;
- арифметические;
- среды выполнения.
Это – основная классификация сбоев в приложениях и операционных системах. Логические, синтаксические и «среды выполнения» встречаются в разработке чаще остальных. На них будет сделан основной акцент.
Ошибки синтаксиса
Синтаксические баги распространены среди новичков. Они относятся к категории «самых безобидных». С данной категорией ошибок способны справиться компиляторы тех или иных языков. Соответствующие инструменты показывают, где допущена неточность. Остается лишь понять, как исправить ее.
Синтаксические ошибки – ошибки синтаксиса, правил языка. Вот пример в Паскале:
Код написан неверно. Согласно действующим синтаксическим нормам, в Pascal в первой строчке нужно в конце поставить точку с запятой.
Логические
Тут стоит выделить обычные и арифметические типы. Вторые возникают, когда программе при работе необходимо вычислить много переменных, но на каком-то этапе расчетов возникают неполадки или нечто непредвиденное. Пример – получение в результатах «бесконечности».
Логические сбои обычного типа – самые сложные и неприятные. Их тяжелее всего обнаружить и исправить. С точки зрения языка программа может быть написана идеально, но работать неправильно. Подобное явление – следствие логической ошибки. Компиляторы их не обнаруживают.
Выше – пример логической ошибки в программе. Тут:
- Происходит сравнение значения i с 15.
- На экран выводится сообщение, если I = 15.
- В заданном цикле i не будет равно 15. Связано это с диапазоном значений – от 1 до 10.
Может показаться, что ошибка безобидная. В приведенном примере так и есть, но в более крупных программах такое явление приводит к серьезным последствиям.
Время выполнения
Run-time сбои – это ошибка времени выполнения программы. Встречается даже когда исходный код лишен логических и синтаксических ошибок. Связаны такие неполадки с ходом выполнения программного продукта. Пример – в процессе функционирования ПО был удален файл, считываемый программой. Если игнорировать подобные неполадки, можно столкнуться с аварийным завершением работы контента.
Самый распространенный пример в данной категории – это неожиданное деление на ноль. Предложенный фрагмент кода с точки зрения синтаксиса и логики написан грамотно. Но, если клиент наберет 0, произойдет сбой системы.
Компиляционный тип
Встречается при разработке на языках высокого уровня. Во время преобразований в машинный тип «что-то идет не так». Причиной служат синтаксические ошибки или сбои непосредственно в компиляторе.
Наличие подобных неполадок делает бета-тестирование невозможным. Компиляционные ошибки устраняются при разработке-отладке.
Ресурсные
Ресурсный тип ошибок – это сбои вроде «переполнение буфера» или «нехватка памяти». Тесно связаны с «железом» устройства. Могут быть вызваны действиями пользователя. Пример – запуск «свежих» игр на стареньких компьютерах.
Исправить ситуацию помогают основательные работы над исходным кодом. А именно – полное переписывание программы или «проблемного» фрагмента.
Взаимодействие
Подразумевается взаимодействие с аппаратным или программным окружением. Пример – ошибка при использовании веб-протоколов. Это приведет к тому, что облачный сервис не будет нормально функционировать. При постоянном возникновении соответствующей неполадки остается один путь – полностью переписывать «проблемный» участок кода, ответственный за соответствующий баг.
Исключения и как избежать багов
Исключение – событие, при возникновении которых начинается «неправильное» поведение программы. Механизм, необходимый для стабилизации обработки неполадок независимо от типа ПО, платформ и иных условий. Помогают разрабатывать единые концепции ответа на баги со стороны операционной системы или контента.
- Программными. Они генерируются приложением или ОС.
- Аппаратными. Создаются процессором. Пример – обращение к невыделенной памяти.
Исключения нужны для охвата критических багов. Избежать неполадок помогут отладчики на этапе разработки. А еще – своевременное поэтапное тестирование программы.
P. S. Большой выбор курсов по тестированию есть и в Otus. Присутствуют варианты как для продвинутых, так и для начинающих пользователей.
Отладка, или debugging, — это поиск (локализация), анализ и устранение ошибок в программном обеспечении, которые были найдены во время тестирования.
Виды ошибок
Это простые ошибки, которые в компилируемых языках программирования выявляет компилятор (программа, которая преобразует текст на языке программирования в набор машинных кодов). Если компилятор показывает несколько ошибок, отладку кода начинают с исправления самой первой, так как она может быть причиной других.
В интерпретируемых языках (например Python) текст программы команда за командой переводится в машинный код и сразу исполняется. К моменту обнаружения ошибки часть программы уже может исполниться.
Ошибки компоновки
Ошибки связаны с разрешением внешних ссылок. Выявляет компоновщик (редактор связей) при объединении модулей программы. Простой пример — ситуация, когда требуется обращение к подпрограмме другого модуля, но при компоновке она не найдена. Ошибки также просто найти и устранить.
Ошибки, которые обнаруживают операционная система, аппаратные средства или пользователи при выполнении программы. Они считаются непредсказуемыми и проявляются после успешной компиляции и компоновки. Можно выделить четыре вида проявления таких ошибок:
- сообщение об ошибке, которую зафиксировали схемы контроля машинных команд. Это может быть переполнение разрядной сетки (когда старшие разряды результата операции не помещаются в выделенной области памяти), «деление на ноль», нарушение адресации и другие;
- сообщение об ошибке, которую зафиксировала операционная система. Она же, как правило, и документирует ошибку. Это нарушение защиты памяти, отсутствие файла с заданным именем, попытка записи на устройство, защищенное от записи;
- прекращение работы компьютера или зависание. Это и простые ошибки, которые не требуют перезагрузки компьютера, и более сложные, когда нужно выключать ПК;
- получение результатов, которые отличаются от ожидаемых. Программа работает стабильно, но выдает некорректный результат, который пользователь воспринимает за истину.
Ошибки выполнения можно разделить на три большие группы.
Ошибки определения данных или неверное определение исходных данных. Они могут появиться во время выполнения операций ввода-вывода.
К ним относятся:
- ошибки преобразования;
- ошибки данных;
- ошибки перезаписи.
Как правило, использование специальных технических средств для отладки (API-логгеров, логов операционной системы, профилировщиков и пр.) и программирование с защитой от ошибок помогает обнаружить и решить лишь часть из них.
Логические ошибки. Они могут возникать из ошибок, которые были допущены при выборе методов, разработке алгоритмов, определении структуры данных, кодировании модуля.
В эту группу входят:
- ошибки некорректного использования переменных. Сюда относятся неправильный выбор типов данных, использование индексов, выходящих за пределы определения массивов, использование переменных до присвоения переменной начального значения, нарушения соответствия типов данных;
- ошибки вычислений. Это некорректная работа с переменными, неправильное преобразование типов данных в процессе вычислений;
- ошибки взаимодействия модулей или межмодульного интерфейса. Это нарушение типов и последовательности при передаче параметров, области действия локальных и глобальных переменных, несоблюдение единства единиц измерения формальных и фактических параметров;
- неправильная реализация логики при программировании.
Ошибки накопления погрешностей. Могут возникать при неправильном округлении, игнорировании ограничений разрядной сетки, использовании приближенных методов вычислений и т.д.