ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 18.03.2025

Просмотров: 208

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
  1. Тестирование и отладка приложений

    1. Виды ошибок

Как показывает программистская практика, ни одну программу реальной степени сложности не удается с первого раза написать без ошибок. Наиболее простыми и поэтому самыми безобидными являются синтаксические ошибки. Синтаксическая ошибка – это нарушение формальных правил написания конструкций языка программирования. Синтаксические ошибки вызывают появление диагностических сообщений. Если причина ошибки не ясна, то нажатием функциональной клавиши F1 можно получать контекстную подсказку и с ее помощью легко разобраться.

Следующей разновидностью можно назвать ошибки, связанные с неправильным применением различных конструкций Delphi. Приложение работает, но делает “не то, что надо” (окна открываются не так или не там, где хотелось бы, отдельные компоненты не работают и т.д.). В таком случае придется просто более внимательно изучать свойства применяемых объектов и разобраться в правилах их использования в своих разработках.

Как и в других языках программирования, так и при работе в Delphi могут встречаться логические ошибки, когда результаты выполнения не соответствуют ожидаемым. Для проверки приложений всегда необходимо проводить тестирование и отладку. Тестирование – это запуск программы на разных наборах исходных данных и анализ полученных результатов. Отладка – это выявление и устранение причин ошибок, если их наличие установлено тестированием. Иногда встречается термин испытание программы, под этим обычно подразумевают определение эксплуатационных характеристик и оценка их соответствия техническому заданию (по времени выполнения, скорости реакции, объему требуемой памяти . . .).

    1. Отладочные средства Delphi

Рассмотрим следующие отладочные средства:

  • трассировка;

  • окна просмотра;

  • точки прерывания (Breakpoints; иногда в литературе их называют контрольными точками).

Трассировка – это выполнение программы по строкам с наблюдением за операторами циклов и разветвлений и промежуточными результатами. Для выполнения трассировки используют следующие функциональные клавиши:

  • F7 выполнение программы по строкам, в том числе внутри процедур и функций;

  • F8 выполнение программы по строкам, но без входа в процедуры и функции, строка с их вызовом рассматривается как один оператор;

  • F4 выполнение программы до курсора.


Трассировка, как правило, бессмысленна без окон просмотра: в них видны значения переменных. Для включения переменной в окно просмотра необходимо поставить курсор на нее и нажать комбинацию клавиш Ctrl+F5. Внешний вид окна просмотра показан на рис. 4.1. В нем имеется две переменных per и s1 до запуска программы, поэтому их значения не определены.

Рис. 4.1. Окно просмотра

Для трассировки программы вместо ее обычного запуска нажимаем на клавишу F7: выполняется трансляция и приложение останавливается на первом исполняемом операторе. При каждом нажатии на F7 выполняется только одна строка программы и изменения значений переменных отражаются в окне просмотра. Во время трассировки текущая строка выделена синей полосой (строка, на которой находится полоса еще не выполнена!). Для наглядности трассировки целесообразно разместить не более одного оператора в строке, а оператор if . . .then . . .else разместить на трех строках, чтобы был виден результат проверки условия. Если программа не содержит процедур и функций, то клавиши F7 и F8 ничем не отличаются. Клавишей F8 лучше пользоваться, если вызываемые процедуры уже отлажены и их построчное выполнение лишь затруднит слежение за логикой программы в целом.

На практике трассировку целесообразно выполнять следующим образом. Определить, какую часть программы необходимо проверять. В качестве такой части можно выбрать процедуру, выполняемую при выборе пункта меню или при нажатии кнопки. Перед первым исполняемым оператором этой процедуры поставим курсор и нажмем на клавишу F4. Приложение запускается и остановится на курсоре. Дальнейшую трассировку выполняем клавишами F7 или F8. Если установим курсор в процедуре, которая соответствует пункту меню, то приложение запускается как обычно и остановится в ожидании выбора из меню. После выбора того пункта, реализацию которого необходимо проверить, происходит остановка на курсоре и можно приступать к трассировке. Если с самого начала пользоваться клавишей F7 (или F8), то приложение остановится в ожидании выбора из меню, а после выбора будет работать до конца, потому что в вызываемой из меню процедуре нет причин, заставляющих ее остановиться. Таким образом, по очереди можно проверять процедуры всех пунктов меню и кнопок. Трассировка особенно полезна для проверки разветвлений и циклов. В разветвлениях можно установить, почему она выполнена неправильно: неправильно написано условие или неправильные данные. В циклах можно следить за постепенным формированием результата, за промежуточными данными, за используемыми и получаемыми на каждом шагу значениями, а также обнаружить причину зацикливания, если такое имеет место. Если в ходе пошагового выполнения ошибку удалось обнаружить, то процесс можно в любой момент остановить выбором подпункта Reset из меню Run.


Точки прерываний предоставляют аналогичный способ проверки приложения. Сначала надо определить, в каких местах программы целесообразно анализировать промежуточные результаты и расставить по ним точки прерываний. Для установки точки прерывания поставим курсор на нужную строку, войдем в меню Delphi, выберем пункт Run и подпункт Add Breakpoint. Точка прерывания выделяется красной полосой. Количество точек прерывания в принципе не ограничено. Можно установить и условные точки прерывания. После выбора пункта меню Add Breakpoint появляется диалоговое окно, в котором имеется строка Condition, в эту строку можно писать условия останова на точке прерывания. Конечно, значения всех переменных, участвующих в этом условии, должны быть определены.

При запуске приложения оно выполняется до первой точки прерывания, при повторном запуске до второй точки и т.д. до конца. Естественно, что если точка прерывания не оказалась на данном пути выполнения программы, то она игнорируется. После остановки программы на точке прерывания можно дальше выполнять ее по строкам, можно добавить переменные в окно просмотра. Имейте в виду, что если точка прерывания установлена внутри цикла, то прерывания происходят на каждом шаге выполнения цикла. Когда отладка закончена, то для удаления точек прерываний войдите в пункт меню View, выберите подпункт View Breakpoints: откроется окно Breakpoints List, в котором перечислены все точки прерывания. Нажатием правой клавиши мыши на этом окне откроется меню, с помощью которого можно их удалить.

В Delphi имеются и другие, более сложные в применении отладочные средства.


    1. Составление тестов

До ввода в эксплуатацию приложение должно быть всесторонне проверено. Дадим в этом параграфе некоторые рекомендации. При разработке событийно-управляемой программы естественно требовать, чтобы она правильно реагировала на все возможные события. Разделим условно события на два класса:

  • события без исходных данных;

  • события с исходными данными.

К первому классу относятся, например, выход из программы, управление расположением окон. Для проверки реакции приложения на такие события надо их просто вызвать и убедиться в правильности реакций на них. Требуется проверить все пункты меню, кнопки нажатия, все возможные комбинации радиокнопок и кнопок выбора.

Сложнее обстоит дело с событиями, которым требуются исходные данные. В таком случае придется заняться составлением тестов. Как показывает практика, много ошибок в программах вызваны просто невнимательностью программистов. Поэтому перечислим здесь ряд вопросов, на которые следует обращать внимание уже на стадии написания программ (в нашем случае процедур реализации пунктов меню, кнопок и собственных алгоритмов):

  1. Существуют ли обращения к переменным, не имеющим значения? Если Вы пользуетесь значениями по умолчанию, убедитесь, что они соответствуют требуемым; лучше присвоить все исходные значения явно.

  2. Находятся ли индексы в допустимых границах? Не забудьте, что в массивах на Pascal’e и в объекте StringGrid разная очередность индексов.

  1. Находятся ли значения переменных в допустимых для данного типа данных границах? Это касается и промежуточных результатов. Проверьте ради интереса, какой будет результат (на Pascal) следующей операции k:=i*j/l; если i, j, l имеют тип Integer; k тип real и i=10000, j=200 и l=20000. Почему? Что надо делать для исправления? А как на Delphi?

  1. Имеются ли вычисления с нечисловыми данными? Нет ли возможности потенциальной ошибки в преобразованиях типов данных? Процедура val( ); функции StrToInt, StrToFloat. . . Согласуются ли типы числовых данных при вычислениях (тип результата деления целых не всегда целый).

  2. Возможны ли недопустимые значения аргументов функций (например, логарифм отрицательного числа), деление на нуль, квадратный корень отрицательного числа?

  3. Соблюдается ли требуемая очередность операций в арифметических и логических выражениях? Простое правило: если сомневаетесь – ставьте скобки, они никогда не мешают. Правильно ли в выражениях расставлены скобки?

  4. Правильно ли расставлены пары Begin. . .End; некоторые программисты рекомендуют: если набрали Begin, наберите сразу же и End и вставьте нужные операторы между ними. Не забудьте, когда за End нужна ; а когда нет!

  5. Существует ли потенциальная возможность зацикливания в циклах while . . do и repeat . . until, изменяется ли условие продолжения (прерывания) цикла по ходу его выполнения?

  6. Соответствуют ли формальные и фактические параметры по количеству, типу и очередности?

  7. Если решается задача, имеющая физическую суть, согласованы ли единицы измерения?


Приведенными здесь вопросами не исчерпываются возможные подводные камни при программировании. Остается лишь рекомендовать: будьте внимательны, часто труднее всего обнаружить самые простые ошибки, потому что никто даже не догадается, что там тоже можно ошибиться.

Имеется два подхода к тестированию:

  • функциональное тестирование (тестирование по данным, тестирование “черного ящика”);

  • структурное тестирование (тестирование по управлению, тестирование “белого ящика”).

При функциональном тестировании структура программы при составлении тестов не используется. Задают исходные данные и анализируют полученный результат.

При структурном тестировании тесты составляют на основе анализа структуры программы.

Наиболее распространенным методом функционального тестирования является эквивалентное разбиение: всю область значений исходных данных разбивают на конечное число классов эквивалентности так, чтобы можно было предположить, что каждый тест, являющийся представителем некоторого класса, эквивалентен любому другому тесту этого класса. Например, исходя из определения модуля y=abs(x), можем выделить два класса эквивалентности: x>=0 и x<0. Различают:

  • правильные классы эквивалентности, представляющие допустимые значения исходных данных;

  • неправильные классы эквивалентности, представляющие недопустимые значения исходных данных.

В примере с модулем неправильным классом эквивалентности является случай, когда вместо х используется нечисловое значение. Для y=ln(x) правильным классом эквивалентности является x>0; неправильными классами x<=0 и нечисловое значение х. Программа должна быть составлена таким образом, чтобы исходные данные из неправильных классов эквивалентности не вызывали программные прерывания во время решения, а лишь сообщение об этом, запрашивание новых исходных данных или возврат в исходное состояние. Например, в системе продажи билетов, если кассир ошибочно ввел дату 30.02, то необходимо запрашивать новую и продолжать работу. Чтобы это обеспечить, программа должна быть протестирована на всех правильных и неправильных классах эквивалентности.

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

if (a>1)AND(b=0) then x:=x/a;

if (a=2)OR(x>1) then x:=x+1;