Тестирование и отладка идут рука об руку, так что большинство программистов просто не воспринимают их как отдельные этапы разработки программ. Однако путь к успеху лежит через разделение процесса отладки и тестирования на два разных этапа работы над программой, и вам следует четко представлять себе, что цель тестирования — определить наличие (или отсутствие) ошибок, В то время как цель отладки — определить местоположение ошибок и устранить их. Поскольку цели этих двух этапов разработки программ различны, различны и используемые для этого методы и инструменты.
Создание
надежного приложения
Лучший путь исключить
ошибки в программе — защититься от них еще при написании кода. Надежное
приложение — приложение, создаваемое с возможностью легко и просто отлаживать
его. Вот основные советы, которые помогут вам уменьшить количество ошибок
при разработке программ.
DataSet:= GetData; //Получение
данных для сортировки.
{$ifdef Debug}
TestResultSet:=
Sort_Tortoise(DataSet); //Медленно и надежно.
{$endif}
ResultSet:=
Sort_Hare(DataSet); //Быстро и рискованно.
{$ifdef Debug}
if not CompareData(ResultSet,
TestResultSet) then
//Результаты совпали?
Raise Exception.Create('Сортировка
в DataSorting некорректна');
{$endif}
Если определен символ Debug, код принимает следующий вид.
DataSet:= GetData; //Получение
данных для сортировки.
TestResultSet:=
Sort_Tortoise(DataSet); //Медленно и надежно.
ResultSet:=
Sort Hare(DataSet); //Быстро и рискованно.
if not CompareData(ResultSet,
TestResultSet) then
//Результаты совпали?
Raise Exception.Create('Сортировка
в DataSorting некорректна');
Если же символ Debug не определен при создании коммерческого варианта программы, код вырождается в алгоритм быстрой сортировки без дополнительных проверок
DataSet:= GetData; //Получение
данных для сортировки.
Re5ultSet:=
Sort_Hare(DataSet); //Быстро и рискованно.
Как видите, использование условной компиляции — простои способ создания как отладочной, так и коммерческой версий приложения Вы можете определить символ условной компиляции двумя путями. Первый — глобальное определение символа в опциях проекта. Выберите команду Project/Options и в диалоговом окне Project Options, во вкладке Directories/Conditionals, введите символ в поле Conditional defines. На рис 2.1 показано определение двух символов (Debug и Alpha) Щелкните на кнопке ОК для подтверждения вашего ввода
Другой метод определения символа условной компиляции — вставить в ваш исходный код директиву.
{$define Debug}
Вероятно, вы не захотите возиться с каждым файлом, входящим в проект, и предпочтете определить символ глобально. Однако возможна ситуация, когда, включив символ условной компиляции глобально, вы захотите отключить его в некоторых модулях. Для этого используйте в файле директиву
{$undef Debug}
Она отключает действие
директивы Debug до тех пор, пока не встретится соответствующая директива
$DEFINE или конец текущего файла.
Конечно, вы можете использовать эти директивы сколь угодно часто и в тех
местах, где сочтете нужным.
Помимо директив условной
компиляции, есть еще немало других директив, которые могут использоваться
в отладочной версии приложения. Я говорю "могут",
поскольку эти директивы могут внести определенные различия в код коммерческой
и тестовой версий, так что будьте осторожны при их применении. Эти опции
перечислены во вкладке Compiler диалогового окна Project Options, приведенного
на рис 2.2
Ниже приведено описание этих опций.
Использование
директивы Assert
Оператор Assert— новый
оператор в Delphi 4. В действительности это просто тест на логическую истину/ложь.
При использовании этого оператора вы убеждаетесь, что логическое выражение
истинно, если при выполнении выражение становится ложным, генерируется
исключительная ситуация. Синтаксис использования оператора таков:
Assert (<логическое выражение)
Вы можете использовать проверку, например, в начале процедуры для выяснения корректности параметров, как показано ниже.
procedure
Foo(Count: Cardinal);
begin
Assert(Count < SizeOf(Word));
end;
Если выражение окажется
ложным, появится сообщение об ошибке, подобное показанному на рис. 2.3.
Конечно же, у вас уже вертится на языке вопрос, чем же это отличается от
конструкции if... else. Дело в том, что управлять генерацией кода для оператора
Assert очень легко и просто с помощью директивы компилятора. Для применения
описанных возможностей используйте директиву $ASSERTIONS ON или $С
+, а для отключения действия Assert— $ASSERTIONS
OFF или $С - (при этом компилятор игнорирует
операторы Assert и код для них не генерируется).
Поскольку вы явно захотите включить эту возможность в отладочную версию и исключить ее из коммерческой, используйте код, подобный приведенному ниже.
{$ifdef Debug}
($ASSERTIONS
ON)
{$else}
($ASSERTIONS
OFF)
{$endif}
Какого типа выражения могут использоваться в операторе Assert? Любого (конечно, если оно возвращает логическое значение). Однако тут есть свои маленькие подводные камушки, о которые легко поцарапаться. Представьте себе, что у вас есть некоторая функция, например выясняющая, сколько раз она была вызвана.
function CountMe:
Integer;
const ReferenceCount:
Integer = 0;
begin
Inc(ReferenceCount);
Result:= ReferenceCount;
end;
Предположим, что вы вызываете ее в операторе Assert. Таким образом, в коммерческой версии, которая игнорирует все операторы Assert, количество вызовов функции будет не таким, как в отладочной версии. Так что будьте внимательны и осторожны.
Модульное
тестирование
Тема модульного тестирования
обширна и многообразна, и писать о ней можно много, но я ограничусь буквально
несколькими словами. Кстати, когда речь идет о модульном тестировании,
слово модуль не имеет отношения к концепции модулей Delphi и подразумевает
функцию, подсистему или другой хорошо определенный программный модуль.
Коротко говоря, идея
модульного тестирования состоит в разбивке приложения на функциональные
единицы и тестировании каждой из них по отдельности. Это
часто означает написание одного или нескольких небольших приложений-оболочек,
цель создания которых — отработать один из модулей вашего приложения.
Ваша задача — выявить все возможные ошибки, так как сообщения о внутренних
ошибках программы, допустимые в тестовых версиях, недопустимы в коммерческих.
Сообщение об ошибках во время работы коммерческой
версии приложения эквивалентны сообщению, приведенному на рис. 2.4
Ну, и наконец, философское замечание о следствии из закона Мэрфи для программирования "В любой работающей программе есть хотя бы одна ошибка, при исправлении которой вносится, по крайней мере, еще две ошибки". Даже в наилучших коммерческих программах содержатся ошибки, а потому вопрос о нахождении и исправлении всех ошибок не может даже быть поставлен. Но следует сделать все возможное, чтобы обнаружить и ликвидировать как можно больше ошибок. Следующий раздел этой главы посвящен описанию инструментов Delphi для локализации и исправления ошибок.