Підручник з Delphi 4

Тестування та налагодження йдуть пліч-о-пліч, так що більшість програмістів просто не сприймають їх як окремі етапи розробки програм. Однак шлях до успіху лежить через поділ процесу налагодження та тестування на два різні етапи роботи над програмою, і вам слід чітко уявляти собі, що мета тестування – визначити наявність (або відсутність) помилок. У той час як мета налагодження – визначити місце розташування помилок та усунути їх. Оскільки цілі цих двох етапів розробки програм різні, різні та використовувані для цього методи та інструменти.

Створення надійної програми Найкращий шлях виключити помилки в програмі - захиститися від них ще під час написання коду. Надійний додаток — додаток, який створюється з можливістю легко і просто налагоджувати його. Ось основні поради, які допоможуть вам зменшити кількість помилок під час розробки програм.

  • Ваша програма повинна бути добре організована. Розділіть програму на модулі, кожен із яких виконує певні завдання. Наприклад, якщо код, що створює звіт, рознесений за десятьма модулями, час налагодження такого коду збільшиться навіть більш ніж у десять разів (хоча б за рахунок пошуку потрібного рядка в десяти модулях). Звичайно, ви можете викликати підпрограми з інших модулів, але вони мають бути створені для виконання чітко поставленого завдання. Безглуздо розміщувати одну половину виконуваної операції в процедурі в одному модулі, а другу половину - в іншій процедурі (тим більше - в іншому модулі). Нехай це примітивна порада, але вона є однією з найдієвіших! Порядок – перш за все! Порядок у думках та у програмі!
  • Захистіть від дурня. Якщо ваша процедура не може переварити некоректні дані і викликати цим крах всієї системи, перевірте цілісність вхідних даних, перш ніж працювати зними. Однак пам'ятайте: якщо системою зможе скористатися будь-який дурень, значить, тільки дурень і нею користуватиметься. Не захоплюйтеся надмірним захистом, який невблаганно буде відбирати час та ресурси, необхідні для виконання важливих завдань.
  • Використовуйте налагоджувальний варіант вашої програми. У налагоджувальній версії програми міститься додатковий код, мета якого – відстежити виконання програми, переконатися в коректності її роботи та спростити налагодження вашої програми. Саме про це й розповідається у наступному підрозділі. Налагоджувальна та комерційна версії коду Ті, хто брали участь у "польових випробуваннях" (відомих як бета-тестрування) комерційних програм, напевно звернули увагу, що такі версії програм більш повільні, набагато "балакучіші" і розміром побільше остаточних версії програм. Може, розробник поспішав і випустив "сирий" продукт, який покращуватиме перед випуском остаточного варіанта? Так теж буває, але головна причина в іншому: у бета-версії міститься тестовий та налагоджувальний коди, які використовуються розробником для перевірки коректності роботи програми. Delphi дозволяє дуже легко внести тестовий та налагоджувальний коди в додаток. Наприклад, ви хочете створити програму роботи з базою даних і використовувати швидкий, але, можливо, дещо ризикований алгоритм сортування даних. Як переконатися в коректності його роботи? Один із шляхів - використовувати в додатку два алгоритми одночасно (швидкий, але ризикований, і повільний, але перевірений), потім порівняти результати роботи обох алгоритмів. Звичайно ж, цей варіант використовується тільки в бета-версії, і після всебічного тестування, якщо все працює відмінно і без збоїв, у кінцевій версії продукту залишиться лише швидкий (і після такого тестування- Вже не ризикований) метод сортування. Для цього вам зовсім не потрібно використовувати два різні тексти програм — скористайтеся можливістю умовного компілювання. Ви можете визначити символ (я зазвичай використовую Debug, але ви вільні у вашому виборі) для перемикання між комерційною та налагоджувальною версіями вашого коду за допомогою директив $IFDEF, $IFNDEF, $ELSE та $ENDIF. Ось приклад використання "повільного" алгоритму у налагоджувальній версії.
  • DataSet: = GetData; //Отримання даних для сортування. TestResultSet:= Sort_Tortoise(DataSet); //Повільно та надійно. ResultSet:= Sort_Hare(DataSet); //Швидко та ризиковано. якщо CompareData(ResultSet, TestResultSet) then //Результати збіглися? Raise Exception.Create('Сортування в DataSorting некоректна');

    Якщо визначено символ Debug, код набуває такого вигляду.

    DataSet: = GetData; //Отримання даних для сортування. TestResultSet: = Sort_Tortoise (DataSet); //Повільно та надійно. ResultSet: = Sort Hare (DataSet); //Швидко та ризиковано. якщо CompareData(ResultSet, TestResultSet) then //Результати збіглися? Raise Exception.Create('Сортування в DataSorting некоректна');

    Якщо символ Debug не визначено під час створення комерційного варіанта програми, код вироджується в алгоритм швидкого сортування без додаткових перевірок

    DataSet: = GetData; //Отримання даних для сортування. Re5ultSet:= Sort_Hare(DataSet); //Швидко та ризиковано.

    Як бачите, використання умовної компіляції — простий спосіб створення як налагоджувальної, так і комерційної версій програми Ви можете визначити символ умовної компіляції двома шляхами. Перший - глобальне визначення символу в опціях проекту. Виберіть Project/Options та у діалоговому вікні ProjectOptions, у вкладці Directories/Conditionals, введіть символ у полі Conditional defi nes. На рис 2.1 показано визначення двох символів (Debug та Alpha) Клацніть на кнопці ОК для підтвердження вашого введення

    Порада: Змінивши символи умовної компіляції, перекомпілюйте проект за допомогою команди Project/Build All, щоб врахувати внесені зміни.

    Інший метод визначення символу умовної компіляції - вставити у вихідний код директиву.

    Ймовірно, ви не захочете возитися з кожним файлом, що входить до проекту, і віддасте перевагу визначити символ глобально. Однак можлива ситуація, коли, увімкнувши символ умовної компіляції глобально, ви захочете вимкнути його в деяких модулях . Для цього використовуйте у файлі директиву

    Вона відключає дію директиви Debug, доки не зустрінеться відповідна директива $DEFINE або кінець поточного файлу . Звичайно, ви можете використовувати ці директиви як завгодно часто і в тих місцях, де вважаєте за потрібне. Крім директив умовної компіляції, є ще чимало інших директив, які можуть використовуватися у налагоджувальній версії програми. Я говорю "можуть", оскільки ці директиви можуть внести певні відмінності в код комерційної та тестової версій, так що будьте обережні при їх застосуванні. Ці опції перераховані у вкладці Compiler діалогового вікна Project Options, наведеного на рис. 2.2. 2.1. Використання діалогового вікна Project Options визначення символів умовної компіляції

    Assert
    Рис 2.2 . Використання діалогового вікна Project Options для зміни налагоджувальних опцій компілятора

    Нижче наведено опис цих опцій.

  • Optimization. Ця опція керує оптимізацією компілятора. Рекомендується залишити цю опцію включеною та вимикати її, якщо ви вважаєте, щооптимізація вносить помилки у вашу програму. Керувати оптимізацією локально можна за допомогою директив компілятора $0+ і $0-.
  • Stack Frames. Якщо ця установка увімкнена, компілятор завжди включає в функцію код для генерації кадру стека, навіть якщо код не використовує стек. Як і у випадку оптимізації, вам навряд чи варто змінювати цю установку. Локальні директиви компілятора - $ W-t і $ W-.
  • Range Checking. Перевірка діапазону перехоплює помилки, викликані виходом межі масиву чи рядки. Однак додатковий код стримує виконання програми і, мабуть, ви відключите цю опцію в комерційній версії. Директиви компілятора для включення та вимикання перевірки - $ R + і $ R -.
  • Assertions (С). Ця опція більш повно описана у наступному розділі. Використання даного типу перевірок дозволяє швидко і просто додати перевірки до коду Природно, в комерційній версії ви захочете відключити цю можливість. Директиви компілятора-$С+ і $С-.
  • Overflow checking (Q). Перевірка на переповнення дозволяє з'ясувати, чи результат виконання цілочисленної операції занадто великим для розміщення його в змінній. Подібно до опції Range Checking, дана опція корисна тільки при налагодженні, і в комерційній версії, як правило, відключається. Директиви компілятора - $ Q + і $ Q -. Налагоджувальна версія вашого коду, ймовірно, буде більшою за розміром і повільніше комерційної версії. Тому не передайте випадково кінцевому користувачеві налагоджувальну версію!
  • Використання директиви Assert Оператор Assert - новий оператор у Delphi 4. Насправді це просто тест на логічну істину/брехню. При використанні цього оператора ви переконуєтесь, що логічний вираз істинний, якщо при виконанні вираз стає хибним, генеруєтьсявиняткова ситуація. Синтаксис використання оператора такий:

    Ви можете використовувати перевірку, наприклад, на початку процедури для з'ясування коректності параметрів, як показано нижче.

    procedure Foo(Count: Cardinal); begin Assert(Count end;

    Якщо вираз виявиться хибним, з'явиться повідомлення про помилку, подібне до показаного на рис. 2.3. Звичайно ж, у вас вже крутиться на мові питання, чим це відрізняється від конструкції if. else. Справа в тому, що керувати генерацією коду для оператора Assert дуже легко та просто за допомогою директиви компілятора. Для використання описаних можливостей використовуйте директиву $ASSERTIONS ON або $С+, а для відключення дії Assert—$ASSERTIONS OFF або $С - (при цьому компілятор ігнорує оператори Assert і код для них не генерується).

    DataSet
    Мал. 2.3. Повідомлення про помилку Assert

    Оскільки ви явно захочете включити цю можливість у налагоджувальну версію та виключити її з комерційної, використовуйте код, подібний до наведеного нижче.

    Який тип виразу може використовуватися в операторі Assert? Будь-якого (звичайно, якщо воно повертає логічне значення). Однак тут є свої маленькі підводні камінці, про які легко подряпатися. Уявіть собі, що у вас є деяка функція, наприклад, яка з'ясовує, скільки разів вона була викликана.

    function CountMe: Integer; const ReferenceCount: Integer = 0; begin Inc(ReferenceCount); Result:= ReferenceCount; end;

    Припустимо, що ви викликаєте в оператора Assert. Таким чином, у комерційній версії, яка ігнорує всі оператори Assert, кількість викликів функції буде не такою, як у версії налагодження. Тож будьте уважні та обережні.

    Модульне тестування Тема модульного тестування велика і різноманітна, іписати про неї можна багато, але я обмежуся буквально кількома словами. До речі, коли йдеться про модульне тестування, слово модуль не має відношення до концепції модулів Delphi і має на увазі функцію, підсистему або інший добре визначений програмний модуль. Коротко кажучи, ідея модульного тестування полягає в розбивці програми на функціональні одиниці та тестуванні кожної з них окремо. Це часто означає написання одного або декількох невеликих додатків-оболонок, мета створення яких - відпрацювати один із модулів вашого додатка. Ваше завдання - виявити всі можливі помилки, оскільки повідомлення про внутрішні помилки програми, допустимі в тестових версіях, неприпустимі в комерційних. Повідомлення про помилки під час роботи комерційної версії програми еквівалентні повідомленню, наведеному на рис. 2.4

    Assert
    Мал. 2.4. Про що думають користувачі, коли програма виводить повідомлення про помилку.