Отладка и тестирование программ. Отладка программы Этапы тестирования и отладки программных средств

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

Искусство тестера состоит в том, чтобы создать по возможности полную систему тестов, проверяющую все возможные ветви вычислений. Поясним это на самом простом примере. Пусть программа находит сумму первых N элементов массива X , содержащего M элементов. Кроме "нормального" теста, проверяющего ситуацию, в которой 1M . Но это простой случай, а циклы обычно вложенные, и внутри них производится разбор случаев, внутри которых свои циклы.

Ранее мы упоминали закон "чечако" - новичок может подвесить любую систему. Этому есть объяснение, по незнанию, он задаст одно из мало вероятных сочетаний входных данных (работая в визуальной среде, нажмет самую неподходящую для данной ситуации кнопку). Поэтому тестер, ведущий отладку, должен уметь встать и на позицию новичка, система тестов должна гарантировать, что программа корректно работает не только в "нормальных ситуациях", но и имеет "защиту от дурака" и не приведет к зацикливанию или останову в крайних, мало вероятных ситуациях.

Сложность отладки заключается и в том, что, обнаружив и исправив ошибку, вы получаете новую программу, для которой процесс отладки нужно начинать заново, снова пропустив все тесты. Известно, что в программах встречаются заколдованные места, - исправление одной ошибки ведет к появлению новой. В таких случаях лучшим выходом бывает поиск другого, принципиально иного решения задачи.

Средства отладки

Часть ошибок программы ловится автоматически еще на этапе компиляции. Сюда относятся все синтаксические ошибки, ошибки несоответствия типов и некоторые другие. Однако синтаксически корректная программа нуждается в отладке, поскольку, хотя результаты вычислений и получены, но они не соответствуют требуемым спецификациям. Чаще всего, еще не отлаженная программа на одних исходных данных работает правильно, на других - дает ошибочный результат. Искусство отладки состоит в том, чтобы обнаружить все ситуации, в которых работа программы приводит к ошибочным вычислениям. VBA обладает весьма изощренными средствами, предназначенными для отладки программ, т.е. для обнаружения ошибок в программах (тестирования) и их исправления. Есть две группы средств VBA, помогающие программисту выявить и исправить ошибки:

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

Прежде, чем приступить к подробному рассмотрению этих средств, напомним, что в ходе отладки программа может находиться в одном из трех состояний: проектирования, вычисления и прерывания. Закончив проектирование, можно запустить программу на исполнение. Прервав исполнение программы в заданной точке, перейдя в состояние прерывания, можно проконтролировать значения переменных и свойств объектов в данной точке и, если требуется, изменить эти значения "вручную". При этом можно изменить порядок выполняемых операторов, задавать следующий исполняемый оператор, можно редактировать программный текст перед продолжением вычисления. Переход из состояния вычисления в состояние прерывания может происходить по самым разным причинам, например, по достижении точки прерывания, при выполнении одного из многочисленных условий прерывания, из-за пошагового выполнения программы. Все эти возможности мы еще обсудим, а сейчас рассмотрим один особый случай. Иногда программа "зацикливается" и необходимо принудительно перевести ее в с остояние прерывания. Как остановить работающую программу? Просто нажмите знакомую еще по работе в DOS пару клавиш Ctrl+Break. На экране появится следующее диалоговое окно с сообщением об остановке.

Типичный цикл разработки, за время жизни программы многократно повторяющийся, выглядит примерно так:

1Программирование - внесение в программу новой функциональности, исправление ошибок в имеющейся.

2Тестирование (ручное или автоматизированное; программистом, тестером или пользователем; «дымовое», в режиме чёрного ящика или модульное…) - обнаружение факта ошибки.

3Воспроизведение ошибки - выяснение условий, при которых ошибка случается. Это может оказаться непростой задачей при программировании параллельных процессов и при некоторых необычных ошибках, известных как гейзенбаги.

4Отладка - обнаружение причины ошибки.

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

    синтаксические;

    ошибки времени выполнения;

    алгоритмические.

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

После возникновения такой ошибки необходимо нажать «Ok» в окне сообщения об ошибке, а затем завершить выполнение программы – пункт меню « Run / Program reset » или нажать комбинацию клавиш <Ctrl ><F 2 >. При возникновении такой ошибки курсор в программе будет указывать на строку, вызвавшую ошибку. Наиболее сложно обнаружить алгоритмические ошибки. Программа компилируется без ошибок, не дает ошибок при пробных запусках, но при анализе результатов выясняется, что результат неправильный. Необходимо вручную «прокрутить» алгоритм – требуется отладка программы .

Для трассировки программы (проверка «логики алгоритма»), т. е. выполнения программы по шагам, необходимо выполнить следующие действия. В пункте меню выбрать пункт «Run / Step over » или «Run / Trace in to » (клавиши <F 8 > и <F 7 > соответственно), команда «Run / Trace in to » отличаются более детальной трассировкой. Для прекращения трассировки и продолжения выполнения программы в автоматическом режиме необходимо выбрать пункт «Run / Run » или нажать <F 9 >. Остановить программу можно с помощью команды «Run / Program reset » или нажать комбинацию клавиш <Ctrl ><F 2 >. Иногда необходимо выполнить трассировку с определенной строки программы. Для этого курсор подводят к интересующей строке и выполняют команду «Run / Run to cursor » или нажимают <F 4 >. Часто известно возможное место ошибки в алгоритме – тогда используют точку останова . Программист устанавливает на нужной строке курсор и ставит там точку останова с помощью команды «Run / Add Breakpoint » или нажав <F 5 >. Выбранная строка будет отмечена. Для снятия точки останова необходимо на этой строке снова нажать <F 5 >. При выполнении программа дойдёт до точки останова, затем программист сможет трассировать программу с помощью <F 7 > и <F 8 >. При необходимости можно указать условие остановки на точке останова (эта настройка осуществляется в окне «Breakpoints », пункт меню «Run / Add breakpoints »).

При выполнении программы по шагам часто необходимо не только проверять правильность «логики алгоритма», но и знать значения некоторых переменных. Для этого выполняют команду «View / Watch / Add watch » и вводят имя интересующей переменной либо подводят курсор к переменной, значение которой необходимо просмотреть, и нажимают <Ctrl ><F 5 >. При трассировке программы в этом случае в окне «Watch list » можно наблюдать изменение значений интересующих переменных.

10. Создание и описание новых типов данных.

Новые типы данных. Когда необходимо объявить свой тип данных, то следует поместить его описание в разделе описания типов. В общем случае описание типов выглядит так:

Имя = Описание типа;

Имя – имя нового типа;

Описание типа описание возможных значений переменных созданного типа.

Замечание. При описании нового типа после имени типа ставится знак «равно», затем следует описание типа.

Примеры

DayOfWeek = (Monday, Wednesday, Friday);

Day =1..31;

Тип подобного вида называется перечисляемым, переменные данного типа могут принимать только перечисленные значения. В примере это одно из названий дня недели (тип DayOfWeek ) или одно из чисел от 1 до 31 (тип Day ). С переменными перечисляемого типа можно использовать функции Pred (переменная)и Succ (переменная), возвращающие предыдущее (Pred ) и последующее (Succ ) из допустимых значений.

Примеры

Пусть объявлены переменные W: DayOfWeek и D: Day. Тогда:

Succ (W); {Оператор вернет значение ‘Monday’}

Pred (D); {Оператор вернет значение ‘4’}

Замечания:

    Значения перечисляемого типа не могут содержать русские буквы.

    Обращение с помощью оператора Succ или Pred к последнему (для оператора Succ ) или первому (для оператора Pred ) элементу приведет к ошибке.

Начинается самый трудоемкий и, в профессиональном плане, самый сложный этап разработки приложения – ОТЛАДКА ПРОГРАММЫ. Сложно написать программу сразу без ошибок. И при этом ошибки бывают разные как по природе из возникновения, так и по трудоемкости исправления.

Самые простые ошибки – синтаксические. Их интерпретатор VBA «вылавливает» сразу, как только Вы нажимаете на клавишу Enter после ввода очередной строки кода программы. Вам остается только внимательно вчитаться в напечатанный Вами текст, найти и исправить опечатку.

Более сложные ошибки – ошибки ВЫПОЛНЕНИЯ ПРОГРАММЫ. Они проявляются только во время работы программы. Вот ими мы и займемся.

Запуск программы на выполнение

Запустить программу в VBA можно несколькими путями.

Запуск через главное меню приложения – самый длинный, но и в то же время, самый типовой прием. Перейдите на лист EXCEL, наберите на чистом листе табличку рисунок 11а, выделите ее как блок (либо мышкой, либо другим путем), поскольку наша программа начнет свою работу с поиска выделенного блока.

Войдите в меню СЕРВИС-МАКРОС-МАКРОСЫ (или Alt+F8) и вы получите окно со списками всех программных модулей (макросов), какие есть сейчас у Вас в приложении (рисунок 13). В нашем случае виден только один макрос – это наша подпрограмма Poradok. Установите на нее курсор и нажмите кнопку ВЫПОЛНИТЬ.

Миг и наша таблица на экране превращается в нечто, следующего вида:


Что-то это не похоже на нужную нам сортировку.

Половина начальных цифр исчезла, появились пустые клетки… Значит где-то в нашей программе «дыра». И может быть не одна. Ну что же, приступим, как говорят хирурги, беря в руки скальпель.

Инструменты отладки программ в vba.

Во-первых снова восстановим на листе EXCEL исходную таблицу рисунок 11а и выделим ее блоком. После этого клавишами Alt+F11 перейдем в инструментальную среду программирования VBA (ИС VBA).

Сначала проверим правильность работы блоков ввода данных. Для этого поставим точку останова программы на оператор следующий за блоком «Получить из выделенной зоны данные “. Точка останова ставится щелчком левой кнопки мыши на левом поле окна модуля с текстом программы напротив того оператора, на котором должна остановиться программа при своем выполнении (появляется коричневая жирная точка, и вся помеченная строка тоже становится коричневая).

Для запуска программы нажмем кнопку запуска приложения , расположенную в инструментальной линейке ИС VBA вверху экрана. Приложение запустится сразу, если ИС VBA разобралась в обстановке, или опять появится окно рисунок 13, если ИС VBA требуются пояснения, что же все-таки следует запустить. После запуска практически сразу программа остановится на нашей «точке останова», что будет видно по ярко желтой полосе на тексте программы. Теперь мы можем проанализировать ситуацию, создавшуюся в программе в текущему моменту. Для анализа раскроем окно локальных переменных (см. выше) и в нем, как в окне системного ПРОВОДНИКА откроем содержимое компонентов массива Mass (рисунок 14).

Видно, что к моменту, когда все данные с экрана должны быть перенесены в этот массив, на самом деле элемент Mass(1,1) – пустой, Mass(1,2) – тоже пустой, а элемент Mass(1,2) содержит 5, хотя должен содержать (см.рисунок 11а) – 8. Значит что-то не в порядке с циклом переноса данных в массив Mass. Анализируем его и видим, что в строке

Mass(i, j) = Cells(X + i, Y + j - 1)

при наборе текста программы мы пропустили -1 в первом индексе ячейки. Исправим эту ошибку:

Mass(i, j) = Cells(X + i - 1, Y + j - 1)

Остановим работу программы кнопкойв инструментальной линейке ИС VBA и снова запустим кнопкой. Теперь содержимое массива Mass в окне локальных переменных (рисунок 15) соответствует действительности.

Пока программа находится в состоянии останова, проверим также содержимое переменных X, Y, H и W. Их можно тоже посмотреть в окне локальных переменных, либо на них можно просто навести курсор мыши в любом месте текста программы и на секунду задержать его. ИС VBA тут же покажет небольшое окошко с содержимым указанной переменной (рисунок 16). Посмотрев все переменные убеждаемся, что блок ввода данных отработал нормально и во всех ячейках разместил именно те числа, которые должны быть.

П

Рисунок 17

родолжим выполнение программы и посмотрим, как она переставит числа теперь. Для продолжения нажмем кнопку. Программа быстро завершилась, что видно по очистке окна локальных переменных (после завершения программы все переменные уходят из поля видимости ИС VBA). Чтобы посмотреть результат переключимся на лист EXCEL. Видим таблицу рисунок 17. Чувство радости при внимательном рассмотрении таблицы сменяется унынием. Перестановка произошла, но как-то не до конца. В частности цифра 1 оказалась после цифры 5. Значит где-то еще «дыра». И скорее всего в блоке перестановки данных. Что ж, продолжим операцию отладки.

Опять придется восстановить таблицу на листе EXCEL в исходное состояние и выделить ее блоком. Снова переключимся в ИС VBA и запустим программу.

Программа остановится на «точке останова» сразу после ввода данных. Чтобы выяснить что происходит при перестановке чисел продолжим выполнение программы в пошаговом режиме.

Если вы откроете меню ОТЛАДКА в верхней строке ИС VBA, то увидите, что режимов пошаговой отладки три. Они вызываются горячими клавишами F8, Shift+F8 и Ctrl+Shift+F8. Названия режимов написаны там же в меню. Нам нужен первый режим: «с заходом» в каждый оператор программы. Поэтому закрываем меню и нажимаем F8. Программа выполнила следующий оператор и остановилась. Теперь Вы можете проанализировать содержимое всех переменных в программе и оценить правильность хода выполнения программы. Снова нажимаете F8 и снова анализ. И так до тех пор пока не выявите ошибку или пока не закончится программа.

Предположим, что произошло второе, а мы так и не заметили где же наша программа ошибается. Тогда немного изменим технологию контроля за ходом выполнения программы. В циклах перестановки в нашей программе сравниваются всего пара ячеек Mass(i,j) и Mass(K,M). Настроим ИС VBA так, чтобы она показывала нам именно эти сравниваемые величины и индексы K и M, целевой ячейки (индексы i, j настольно просто изменяются, что ошибиться в них невозможно (почти)).

Для контроля используем окно контрольных значений (меню ВИД…). Чтобы добавить в окно интересующие нас величины удобно выделить их в тексте программы, щелкнуть правой клавишей мыши и в появившемся динамическом меню выбрать режим «Добавить контрольное значение». Появится окно с настройками контрольного значения (рисунок 19).

Здесь можно откорректировать (или вписать другое) переменную или выражение, которое Вы хотите контролировать и установить тип контроля. В нашем случае тип контроля – контрольное выражение. После нажатия на кнопку ОК, заказанное выражение попадает в окно контрольных значений. Вводим в окно все четыре интересующие нас величины.

Снова восстанавливаем таблицу на листе EXCEL в исходное состояние, выделяем ее блоком. Снова переключаемся в ИС VBA и запускаем программу. Снова, после останова программы, жмем F8, пошагово проходя по каждому оператору и анализируя изменение контрольных значений наших переменных (рисунок 18). И в какой-то момент с удивлением замечаем, что когда на следующем шаге индекс M должен был приобрести значение 1, этого не произошло. Внимательно посмотрев на текст программы, мы наконец замечаем, что пропустили оператор установки переменной L в 1.

Остановим программу. Добавим пропущенный оператор. Снова восстанавливаем таблицу на листе EXCEL в исходное состояние, выделяем ее блоком. Снова переключаемся в ИС VBA. Снимаем точку останова на операторе

For i = 1 To H

(щелчком мыши на нем) и запускаем программу.

Проверяем результат на листе EXCEL:

Ура! Наконец программа выдала то, что нам надо.

Тестируем программу еще и еще раз, выстраивая на листе EXCEL различные таблицы и упорядочивая в них данные. Все работает отлично!

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

Придется порыться в справочной системе VBA, книгах по программированию на VBA и лекциях, чтобы найти функцию, определяющую тип переменной. В справочной системе описание этой функции выглядит так, как показано на рисунок 20. Функция имеет ключевое слово VarType(), в качестве параметра требует переменную, которую Вы хотите проанализировать и возвращает коды, указанные в справке (рисунок 20) в зависимости от типа переменной.

Кроме того, используем стандартную функцию для выдачи сообщений на экран MsgBox и команду принудительного выхода из подпрограммы Exit Sub (как записывается и используется эти функция и команда тоже можно посмотреть в справочной системе VBA).

Код программы, который использует эти функции и удобен для нас выглядит так:

If VarType(obmen) > 1 And VarType(obmen) < 6 Then

Mass(i, j) = obmen

MsgBox "В ячейке "+Chr(Y + i + 63)+LTrim(Str(X + i - 1))+ _

" НЕ числовые данные"

Выводимый на экран текст в функции MsgBox составлен путем сложения отдельных фраз и номеров строки и столбца преобразованных в текст. С помощью стандартной функции языка Basic – Chr код столбца преобразовывается в букву его названия (но при этом, чтобы получилась буква к коду добавляется число 63 – смещение буква А в кодовой таблице символов).

Стандартная функция LTrim удаляет все левые пробелы из строки, в которую стандартная функция Str преобразовала число с номером строки ячейки. Обо всех этих функциях Вы более подробно можете посмотреть в справочной системе VBA.

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

Cells(X, Y).Select

которая переводит курсор выделения ячеек на ячейку в начале выделенной таблицы.

После внесения всех изменений окончательный текст нашей программы принимает вид:

Dim Mass() As Variant

Dim obmen As Variant

Dim i As Integer

Dim j As Integer

Dim X As Integer

Dim Y As Integer

Dim H As Integer

Dim W As Integer

Dim K As Integer

Dim L As Integer

Dim M As Integer

"Получить характеристики выделенной области

X = Selection.Row

Y = Selection.Column

H = Selection.Rows.Count

W = Selection.Columns.Count

"Заказать в памяти массив

ReDim Mass(H, W)

"Получить из выделенной зоны данные

obmen = Cells(X + i - 1, Y + j - 1)

If VarType(obmen) > 1 And VarType(obmen) < 6 Then

Mass(i, j) = obmen

MsgBox "В ячейке " + Chr(Y + i + 63) + LTrim(Str(X + i - 1)) + _

" НЕ числовые данные"

"Переставить данные в порядке возрастания

If Mass(i, j) > Mass(K, M) Then

obmen = Mass(i, j)

Mass(i, j) = Mass(K, M)

Mass(K, M) = obmen

"Вывести новый порядок данных на лист EXCEL

Cells(X + i - 1, Y + j - 1) = Mass(i, j)

Цель лекции: ознакомиться с видами и способами контроля и тестирования ПО, методами и средствами отладки программ.

Недостаточно выполнить проектирование и кодирование программного продукта, также необходимо обеспечить его соответствие требованиям и спецификациям. Многократно проводимые исследования показали, что чем раньше обнаруживаются те или иные несоответствия или ошибки, тем боль­ше вероятность их исправления и ниже его стои­мость . Современные технологии разработки ПО преду­сматривают раннее обнаружение ошибок за счет выполнения контроля ре­зультатов всех этапов и стадий разработки. На начальных этапах кон­троль осуществляют вручную или с использованием CASE -средств, на последних - он принимает форму тестирования.

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

    предполагаемые результаты должны быть известны до тестирования;

    следует избегать тестирования программы автором;

    необходимо досконально изучать результаты каждого теста;

    необходимо проверять действия программы на неверных данных;

    необходимо проверять программу на неожиданные побочные эффекты на неверных данных.

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

Существуют два принципиально различных подхода к формированию тестовых наборов: структурный и функциональный . Структурный подход базируется на том, что известна структура тести­руемого ПО, в том числе его алгоритмы («стеклян­ный ящик »). Тесты строятся для проверки правильности реализации заданной логики в коде программы. Функциональный подход основывается на том, что структура ПО не известна («черный ящик »). В этом случае тесты строят, опираясь на функциональные спецификации. Этот подход называют также подходом, управляемым данными, так как при его использовании тесты строят на базе различных способов декомпозиции множества данных. Наборы тестов, полученные в соответствии с методами этих подходов, объединяют, обеспечивая всестороннее тестирование ПО.

Ручной контроль используют на ранних эта­пах разработки. Все проектные решения анализируются с точки зрения их правильности и целесообразности как можно раньше, пока их можно легко пересмотреть. Различают статический и динамический подходы к ручному контролю. При статическом подходе анализируют структуру, управляющие и инфор­мационные связи программы, ее входные и выходные данные. При динамическом - выполняют ручное тестирование (вручную моделируют про­цесс выполнения программы на заданных исходных данных). Исходными данными для таких проверок являются: техническое зада­ние, спецификации, структурная и функциональная схемы программного продукта, схемы отдельных компонентов, а для более поздних этапов - алгоритмы и тексты программ, а также тестовые наборы. Доказано, что ручной контроль способствует существенному увеличе­нию производительности и повышению надежности программ и с его помо­щью можно находить от 30 до 70 % ошибок логического проектирования и кодирования. Основными методами ручного контроля являются: инспекции исходного текста , сквозные просмотры , проверка за столом , оценки программ .

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

Другим способом проверки программ является функциональное тестирование : про­грамма рассматривается как «черный ящик », целью тестирования является выяснение обстоятельств, когда поведение программы не соответствует спецификации. Для обнаружения всех ошибок необходимо выполнить исчерпывающее тестирование (при всех возможных наборах данных), что для большинства случаев невоз­можно. Поэтому обычно выполняют «разумное » или «приемлемое » тестиро­вание, ограничивающееся прогонами программы на небольшом под­множестве всех возможных входных данных. При функциональном тестировании различают следующие методы фор­мирования тестовых наборов: эквивалентное разбиение ; анализ граничных значений ; анализ причинно-следственных связей ; предположение об ошибке .

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

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

Отладка - это процесс локализации (определения оператора программы, выполнение которого вызвало нарушение вычислительного процесса) и исправления ошибок, обнаружен­ных при тестировании ПО. Для исправления ошиб­ки необходимо определить ее причину. Отладка требует от программиста глубоких знаний специфики управления используемыми техническими средствами, операционной системы, среды и языка программирования, реализуемых процессов, природы и специфики ошибок, методик отладки и соответствующих программных средств; психологически дискомфортна (нужно искать собственные ошибки в условиях ограниченного времени); оставляет возможность взаимовлияния ошибок в разных частях программы. Четко сформулированные методики отладки отсутствуют. Различают:

    синтаксические ошибки – сопровождаются комментарием с указанием их мес­тоположения, фиксируются компилятором (транслятором) при выполнении синтаксического и частично се­мантического анализа;

    ошибки компоновки - обнаруживаются компоновщиком (редакто­ром связей) при объединении модулей программы;

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

    ошибки определения исходных данных (ошибки передачи, ошибки преобразования, ошибки перезаписи и ошиб­ки данных);

    логические ошибки проектирования (неприменимый метод, неверный алгоритм, неверная структура данных, другие) и кодирования (ошибки некорректного использования переменных, вычислений, межмодульного интерфейса, реализации алгоритма, другие);

    ошибки накопления погрешностей результатов вычислений (игнорирование ограничений разрядной сетки и способов уменьшения погрешности).

Отладка программы в любом случае предполагает обдумывание и логи­ческое осмысление всей имеющейся информации об ошибке. Большинство ошибок можно обнаружить по косвенным признакам посредством тщатель­ного анализа текстов программ и результатов тестирования без получения дополнительной информации с помощью следующих методов:

      ручного тестирования (при обнаружении ошибки нужно выполнить те­стируемую программу вручную, используя тестовый набор, при работе с ко­торым была обнаружена ошибка);

      индукции (основан на тща­тельном анализе симптомов ошибки, которые могут проявляться как неверные результаты вычислений или как сообщение об ошибке);

      дедукции (вначале формируют множество причин, которые могли бы вызвать данное проявление ошибки, а затем анали­зируя причины, исключают те, которые противоречат имеющимся данным);

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

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

Общая методика отладки программных продуктов, написанных для выполнения в операционных системах MS DOS и Win32:

1 этап - изучение проявления ошибки;

2 этап – определение локализации ошибки;

3 этап - определение причины ошибки;

4 этап - исправление ошибки;

5 этап - повторное тестирование.

Процесс отладки можно существенно упрос­тить, если следовать основным рекомендациям структурного подхода к про­граммированию:

    программу наращивать «сверху-вниз», от интерфейса к обрабатываю­щим подпрограммам, тестируя ее по ходу добавления подпрограмм;

    выводить пользователю вводимые им данные для контроля и прове­рять их на допустимость сразу после ввода;

    предусматривать вывод основных данных во всех узловых точках ал­горитма (ветвлениях, вызовах подпрограмм).

Дополнительную информацию по теме можно получить в .

Отладка (debug, debugging) - этап разработки компьютерной программы, на котором обнаруживают, локализуют и устраняют ошибки. Чтобы понять, где возникла ошибка, приходится: узнавать текущие значения переменных; выяснять, по какому пути выполнялась программа.

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

Технологии отладки.

1) Использование отладчиков - программ, которые включают в себя пользовательский интерфейс для пошагового выполнения программы: оператор за оператором, функция за функцией, с остановками на некоторых строках исходного кода или при достижении определённого условия.

2) Вывод текущего состояния программы с помощью расположенных в критических точках программы операторов вывода - на экран, принтер, громкоговоритель или в файл. Вывод отладочных сведений в файл называется журналированием.

Инструменты отладки.

1. Отладчик – программный инструмент, позволяющий программисту наблюдать за выполнением исследуемой программы, останавливать и перезапускать её, прогонять в замедленном темпе, изменять значения в памяти и даже, в некоторых случаях, возвращать назад по времени.

2. Профилировщики – позволяют определить сколько времени выполняется тот или иной участок кода, а анализ покрытия позволит выявить неисполняемые участки кода.

3. API логгеры – позволяют программисту отследить взаимодействие программы и Windows API при помощи записи сообщений Windows в лог.

4. Дизассемблеры позволят программисту посмотреть ассемблерный код исполняемого файла

5. Сниферы помогут программисту проследить сетевой трафик генерируемой программой

6. Сниферы аппаратных интерфейсов позволят увидеть данные которыми обменивается система и устройство.

7. Логи системы .

Использование языков программирования высокого уровня , таких как Java, обычно упрощает отладку, поскольку содержат такие средства как обработка исключений , сильно облегчающие поиск источника проблемы. В некоторых низкоуровневых языках, таких как Ассемблер , ошибки могут приводить к незаметным проблемам - например, повреждениям памяти или утечкам памяти, и бывает довольно трудно определить, что стало первоначальной причиной ошибки. В этих случаях, могут потребоваться изощрённые приёмы и средства отладки.

Отладка = Тестирование + Поиск ошибок + Редактирование

Виды отладки ПО, включая тестирование (в нашей стране).

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



1.2. Комплексная отладка. Тестирование ПО в целом с поиском и исправлением фиксируемых при тестировании ошибок во всех документах (включая тексты программ ПО), относящихся к ПО в целом. К таким доку-ментам относятся определение требований к ПО, спецификация качества ПО, функциональная спецификация ПО, описание архитектуры П.О. и тексты программ ПО.

2.1. Синтаксическая отладка. Синтаксические ошибки выявляет компилятор, поэтому исправлять их достаточно легко.

2.2. Семантическая (смысловая ) отладка. Ее время наступает тогда, когда синтаксических ошибок не осталось, но результаты программа выдает неверные. Здесь компилятор сам ничего выявить не сможет, хотя в среде программирования обычно существуют вспомогательные средства отладки, о которых мы еще поговорим.

Взаимосвязь процессов тестирования и отладки через алгоритм отладки.

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

При этом тестер или программист заранее должны получить контрольный результат с которым будет идти сверка работы проверяемого кода.

В случае обнаружения расхождений между контрольным и фактическим результатами, начинается поиск проблемного участка кода и выявление ошибок вышеуказанными способами.

Средства автоматического тестирования исходного кода программ.

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

Примерами таких систем могут быть: встроенный модуль doctest в Python и мультиязыковая библиотека тестирования xUnit, распространяемая на условиях GNU/GPL и LGPL. Основа применения всех этих средств и техник это разбиение одной большой задачи на ряд четких и более маленьких задач.


23. Основные принципы объектно-ориентированного программирования: инкапсуляция, наследование, полиморфизм. Отличие объектно-ориентированного подхода от модульного при разработке программ

Объектно-ориентированное программирование (ООП) - парадигма программирования, в которой основными концепциями являются понятия объектов и классов (либо, в менее известном варианте языков с прототипированием, - прототипов).

Прототип - это объект-образец, по образу и подобию которого создаются другие объекты.

Класс

Поля , описанные в классе, используют для хранения составляющих состояния объекта, т.е. поля определяют состояние объектов.

Методы , описанные в классе, определяют поведение объектов. Каждый метод определяет реакцию объекта на некоторое внешнее или внутреннее сообщение.

Объект - переменная типа класс

Принципы объектно-ориентированного программирования.

1. Абстракция. Абстрагирование - это способ выделить набор значимых характеристик объекта, исключая из рассмотрения незначимые. Соответственно, абстракция – это набор всех таких характеристик.

2. Инкапсуляция.

Инкапсуляция - принцип ООП, согласно которому в классе объединяются поля и методы.

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

3. Наследование. Наследование - это свойство системы, позволяющее описать новый класс на основе уже существующего с частично или полностью заимствующейся функциональностью.

Наследование - возможность конструирования новых более сложных классов из уже имеющихся посредством добавления полей и определения новых методов (принцип иерархичности ).

Класс, от которого производится наследование, называется базовым , родительским или суперклассом. Новый класс – потомком , наследником или производным классом. Механизм наследования обеспечивает классу-потомку возможность использования полей и методов родительских классов. Цепочки наследования могут быть неограниченной длины. При этом различные методы для каждого из наследников разрешается переопределять .

4. Полиморфизм. Полиморфизм - это свойство системы использовать объекты с одинаковым интерфейсом без информации о типе и внутренней структуре объекта.

Полиморфизм (“многообразие”) в программировании - возможность изменения кода программы в соответствии со значением некоторых параметров.

4.1. Чистый полиморфизм - возможность различной интерпретации кода функции в зависимости от типа аргументов.

4.2. Перегрузка (полиморфные имена) функций - возможность определения нескольких функций с одним именем; выбор нужной функции может определяться типами аргументов, областью видимости (внутри модуля, файла, класса и т.д.); если выбор определяется типом аргументов, то перегрузка называется параметрической .

4.3. Переопределение методов - в ООП - возможность различных определений методов в классе-потомке и классе-родителе; конкретный метод определяется классом объекта, для которого он вызывается. При переопределении методов различают простой и сложный полиморфизм.

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

4.3.2. Сложный полиморфизм используют, если при вызове переопределенного метода необходимо уточнить, какой метод должен быть подключен: метод родителя или метод потомка, так как объект, для которого вызывается переопределенный метод, может быть как объектом класса родителя, так и объектом класса потомка. В этом случае нужный метод определяется на этапе выполнения программы, когда тип объекта точно известен.

4.4. Обобщенные функции (шаблоны) - возможность описания параметризованных классов и шаблонов функций, параметрами таких описаний являются типы аргументов методов или функций.

Отличие объектно-ориентированного подхода от модульного.

1) Объектно-ориентированный подход к проектированию прогр. продуктов основан на:

− выделении классов объектов;

− установлении характерных свойств объектов и методов их обработки;

− создании иерархии классов, наследовании свойств объектов и методов их обработки.

2) Модульное программирование - это организация программы как совокупности небольших независимых блоков, модулей, структура и поведение которых подчиняется определенным правилам.

Следует заметить, что понятие «модуль» не совпадает в данном случае с понятием «модуль» (в смысле «библиотека») языка Паскаль . Это должна быть простая, замкнутая (независимая) программная единица (процедура или функция), обозримая, реализующая только одну функцию. Для написания одного модуля должно быть достаточно минимальных знаний о тексте других, как вызывающих, так и вызываемых.

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


24. Классы и объекты: их определение, соотношение между ними. Роль составляющих класса – полей, свойств, методов. Спецификаторы доступа published, public, private, protected. Конструкторы и деструкторы, их роль. События и их использование в управлении программой

Класс - это структурный тип данных, который включает описание полей данных, а также процедур и функций, работающих с этими полями данных (методов).

Объект - переменная типа класс - сущность в адресном пространстве вычислительной системы, появляющаяся при создании экземпляра класса (например, после запуска результатов компиляции (и связывания) исходного кода на выполнение).

Соотношение класса и объекта:

Понятие класса является более общим, чем понятие объекта. Объект является экземпляром класса . Класс может рассматриваться как совокупность объектов (подобно тому, как множество есть совокупность элементов). Класс может быть элементарным или подразделяться на подклассы (подобно тому как множество подразделяется на подмножества). Например, класс PERSON содержит подкласс STUDENT, который, в свою очередь, содержит объект John_Smith.

Классы имеют (например, в Delphi):

Поле класса (атрибут ) в ООП - переменная, связанная с классом или объектом. Поля , описанные в классе, используются для хранения составляющих состояния объекта, т.е. поля определяют состояние объектов. Доступ к полям осуществляется по их имени.

Методы , описанные в классе (подпрограммы, которые обрабатывают поля и свойства класса), определяют поведение объектов. Каждый метод определяет реакцию объекта на некоторое внешнее или внутреннее сообщение.

Свойство - способ доступа к внутреннему состоянию объекта, имитирующий переменную некоторого типа. Обращение к свойству объекта реализовано через вызов функции. При попытке задать значение данного свойства вызывается один метод, а при попытке получить значение данного свойства - другой.

Поля, свойства и методы класса называются членами класса .

Переменная, описанная как класс, фактически является указателем на экземпляр класса. В объектно-ориентированной программе с применением классов каждый объект является «экземпляром» некоторого конкретного класса, и других объектов не предусмотрено.

Спецификаторы доступа published, public, private, protected.

Инкапсуляция - это свойство системы, позволяющее объединить данные и методы, работающие с ними, в классе и скрыть детали реализации от пользователя.

По умолчанию (в Delphi) видимость родительских членов класса наследуется в точности, однако разрешено повышать видимость - делать поля, свойства и методы более доступными. Понижение видимости не допускается.

Уровни инкапсуляции (доступность любых членов класса):

1) Public . Члены класса, находящиеся в данном разделе, доступны из любой точки программы.

2) Private . Члены класса доступны только в том модуле, где данный класс описан. По умолчанию считается, что все поля класса расположены в разделе private .

3) Protected . Члены класса доступны в том модуле, где данный класс описан, а также внутри методов классов, являющихся наследниками данного класса и описанных в других модулях.

4) Published . Члены класса, находящиеся в данном разделе, доступны из любой точки программы. В этом разделе располагаются свойства класса: поля, доступные для редактирования и изменения значений во время проектирования и из Инспектора объектов .

5) Automated . Члены класса, находящиеся в данном разделе, доступны из любой точки программы. Описания разрешается размещать в этом разделе, только если класс является наследником стандартного класса TAutoObject (в Delphi), предназначенного для создания так называемых серверов автоматизации при использовании технологии СОМ (Competent Object Model).

Конструкторы и деструкторы.

Когда объект создается , однократно вызывается специальный метод, называемый конструктором . В нем выполняются различные действия по начальной инициализации полей объекта.

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

События и их использование в управлении программой.

Событие в ООП - это сообщение, которое возникает в различных точках исполняемого кода при выполнении определённых условий.

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

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


25. Основные отличия языка Object Pascal (Delphi) от Turbo Pascal. Динамические массивы в Delphi: описание, особенности, применение

Turbo Pascal - интегрированная среда разработки для языка программирования Pascal и язык программирования в этой среде, диалект языка Паскаль от фирмы Borland.

Delphi - среда программирования, в которой используется язык программирования Object Pascal.

Object Pascal - результат развития языка Turbo Pascal , который, в свою очередь, развился из языка Pascal . Pascal был полностью процедурным языком.

Turbo Pascal , начиная с версии 5.5, добавил в Pascal объектно-ориентированные свойства, а в Object Pascal - динамическую идентификацию типа данных с возможностью доступа к метаданным классов (то есть к описанию классов и их членов) в компилируемом коде, также называемом интроспекцией - данная технология получила обозначение RTTI.

Так как все классы наследуют функции базового класса TObject, то любой указатель на объект можно преобразовать к нему, после чего воспользоваться методом ClassType и функцией TypeInfo, которые и обеспечат интроспекцию.

Object Pascal (Delphi ) является результатом функционального расширения Turbo Pascal.

Объектная модель Delphi Pascal по сравнению с моделью, использованной Borland Pascal 7.0, является более полной:

− ограничение доступа к полям и методам за счет определения собственного интерфейса к каждому полю класса (пять типов секций при объявлении класса, использование свойств);

− более развитые механизмы реализации полиморфных методов (абстрактные, динамические методы)",

− средства работы с метаклассами (переменные метаклассов, методы классов, механизм RTTI).

Динамические массивы в Delphi.

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

Объявление массива: var My_Array: array of BaseType;

При таком объявлении память не выделятся, и первоначальный размер массива - нулевой .

Установка размера массива: SetLength(My_Array,100);

Получение числа элементов массива: n:=Length(My_Array);

Обращение к первому элементу массива: My_Array:=10; x:=My_Array;

Объявление двумерного массива: var A: array of array of BaseType;

Если присвоить переменной динамический массив, то его содержимое не копируется, присваивается только указатель на массив. А вот если применить к новому массиву SetLength , то тогда и произойдет копирование.


26. Структура модулей в Delphi. Интерфейсная, исполняемая части, инициирующая и завершающая части. Процедуры и функции: особенности в Delphi

Проект в Delphi представляет собой набор программных единиц – модулей.

Delphi позволяет поместить свои функции и процедуры в отдельный модуль (Unit ), а затем использовать процедуры и функции модуля в своих программах, указав имя модуля в списке модулей, необходимых программе (инструкция uses ). Модуль – это файл с расширением *.pas.

Начинается модуль заголовком - инструкцией unit , в которой указано имя модуля.

Модуль состоит из последовательности разделов . Каждый раздел начинается ключевым словом и продолжается до начала следующего раздела. В раздел implementation (реализация) нужно поместить процедуры и функции, объявленные в разделе interface .

Структура модулей в Delphi.

Unit <имя>;

Interface <интерфейсная часть>

Implementation <исполняемая часть>

initialization <инициирующая часть>

finalization <завершающая часть>

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

unit ИмяМодуля;

interface // раздел интерфейса

{ Описания процедур и функций модуля, которые могут использоваться другими модулями. }

const // раздел объявления констант

{ Объявления глобальных констант модуля, которые могут использоваться процедурами и функциями модуля.}

type // раздал объявления типов

{ Объявления глобальных типов модуля, которые могут использоваться процедурами и функциями модуля }

var // раздел объявления переменных

{ Объявления глобальных переменных модуля, которые могут использоваться процедурами и функциями модуля}

implementation // раздел реализации

{ Описания (текст) процедур и функций модуля!}

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

Процедуры и функции в Delphi.

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

Процедура - это разновидность подпрограммы. Обычно подпрограмма реализуется как процедура в двух случаях:

− когда подпрограмма не возвращает в основную программу никаких данных;

− когда подпрограмма возвращает в вызвавшую ее программу больше чем одно значение.

Параметры – это входные данные.

Объявление процедуры

procedure ИмяПроцедуры {var параметр1: тип1; … var параметр К: тип К);