THE BELL

Есть те, кто прочитали эту новость раньше вас.
Подпишитесь, чтобы получать статьи свежими.
Email
Имя
Фамилия
Как вы хотите читать The Bell
Без спама

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Цель работы:

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

Порядок выполнения работы и отчетность.

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

Составленный набор тестов необходимо представить в отчете.

Теоретические сведения.

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

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

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

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

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

Комплект тестов должен быть таким:

Чтобы проверить все варианты внешнего эффекта программы и ва­рианты ее внутренней работы алгоритма;

Чтобы все ветви алгоритма были пройдены, по крайней мере, по од­ному разу.

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

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

Процесс тестирования программы можно разделить на три этапа:

1. Проверка в нормальных условиях.

2. Проверка в экстремальных условиях.

3. Проверка в исключительных ситуациях.

Каждый из этих трех этапов проверки должен гарантировать по­лучение верных результатов при правильных входных данных и выдачу сообщений об ошибках при неправильных входных данных.

Проверка в нормальных условиях

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

Проверка в экстремальных условиях

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

Проверка в исключительных ситуациях.

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

Пример тестов.

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

Стороны

Параллепипеда

Примечание

Хороший нормальный тест d 1,7320508

Понятия «отладка», «отладка программы». Процесс отладки. Виды (методика) отладок, приемы отладки.

После того как процесс проектирования формы завершен и программный код написан, необходимо откомпилировать программу. В процессе компиляции следует исправить не только ошибки, но и замечания. Большинство ошибок имеют синтаксический характер. Часто сообщения о такой ошибке возникают еще на стадии написания программного кода. Если ошибка не исправлена пользователем, то текст оператора будет выделен красным цветом. Если ошибки при компиляции исправлены, то при запуске приложения вовсе необязательно, что не возникнет новых ошибок. Это могут быть логические ошибки. Могут появиться ошибки при определенных данных: деление на 0, переполнение, извлечение квадратного корня из отрицательного числа, отсутствие инициализации в начале вычислений, открытие несуществующего файла и др.
При появлении исключительных ситуаций на этапе выполнения приложений компилятор сообщает об этом пользователю в диалоговом окне.
При прерывании работы приложения строка будет отмечена желтым цветом, если диалоговое окно будет закрыто при нажатии кнопки Debug - Отладка. Если сообщение об ошибке было закрыто кнопкой End - Закончить, то будет отмечен заголовок процедуры, в которой найдена ошибка.

Отладка программы

Отладка, как мы уже говорили, бывает двух видов:

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

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

Отладка - это процесс локализации и исправления ошибок в программе.

Принципы отладки

Принципы локализации ошибок:

· Большинство ошибок обнаруживается вообще без запуска программы - просто внимательным просматриванием текста.

· Если отладка зашла в тупик и обнаружить ошибку не удается, лучше отложить программу. Когда глаз "замылен", эффективность работы упорно стремится к нулю.

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

· Экспериментирования типа "а что будет, если изменить плюс на минус" - нужно избегать всеми силами. Обычно это не дает результатов, а только больше запутывает процесс отладки, да еще и добавляет новые ошибки.

Принципы исправления ошибок еще больше похожи на законы Мерфи:

· Там, где найдена одна ошибка, возможно, есть и другие.

· Вероятность, что ошибка найдена правильно, никогда не равна ста процентам.

· Наша задача - найти саму ошибку, а не ее симптом.

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

· Исправляя одну ошибку, очень легко внести в программу еще парочку. "Наведенные" ошибки - настоящий бич отладки.

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

Методы отладки.

1.Силовые методы

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

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

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

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

Суммируя свойства силовых методов, получаем практические советы:

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

o использовать отладочную печать в небольших количества и "по делу";

o оставить дамп памяти на самый крайний случай.

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

3.Метод дедукции - от общего к частному.
Выдвигаем гипотезу, которая может объяснить ошибку, пусть и не полностью. Затем при помощи тестов эта гипотеза проверяется и доказывается.

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

5.Метод тестирования.

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

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

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

Автоматизированные средства отладки программ.

Стандартные возможности отладчика. Контроль правильности написанной программы (этапы).

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

Помимо методик, хорошо бы иметь представление о средствах, которые помогают нам выявлять ошибки. Это:

1) Аварийная печать - вывод сообщений о ненормальном завершении отдельных блоков и всей программы в целом.

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

3) Непосредственное слежение:

· арифметическое (за тем, чему равны, когда и как изменяются выбранные переменные),

· логическое (когда и как выполняется выбранная последовательность операторов),

· контроль выхода индексов за допустимые пределы,

· отслеживание обращений к переменным,

· отслеживание обращений к подпрограммам,

· проверка значений индексов элементов массивов и т.д.

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

· просмотреть текущие значения переменных, состояние памяти, участок алгоритма, где произошел сбой;

· прервать выполнение программы;

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

Автономное тестирование модуля целесообразно осуществлять в четыре последовательно выполняемых шага.

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

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

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

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

Советы отладчику

1) Проверяйте тщательнее: ошибка скорее всего находится не в том месте, в котором кажется.

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

3) Тщательнее следить за объявлениями констант, типов и переменных, входными данными.

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

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

· значения входных аргументов принимаются не в том порядке,

· переменная не проинициализирована,

· при повторном прохождении модуля, перемен ная повторно не инициализируется,

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

· скобки в сложном выражении расставлены неправильно.

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

7) Ошибка, скорее всего окажется вашей и будет находиться в тексте программы. Гораздо реже она оказывается:

· в компиляторе,

· операционной системе,

· аппаратной части,

· электропроводке в здании и т.д.

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

8) Убедитесь, что исходный текст программы соответствует скомпилированному объектному коду (текст может быть изменен, а запускаемый модуль, который вы тестируете - скомпилирован еще из старого варианта).

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

10) Старайтесь не жалеть времени, чтобы уясненить причину ошибки. Это поможет вам:

· исправить программу,

· обнаружить другие ошибки того же типа,

· не делать их в дальнейшем.

11) Если вы уже знаете симптомы ошибки, иногда полезно не исправлять ее сразу, а на фоне известного поведения программы поискать другие ляпы.

12) Самые труднообнаруживаемые ошибки - наведенные, то есть те, что были внесены в код при исправлении других.

оверкой называется проверка результатов тестирования самой тестируемой программой

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

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

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

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

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

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

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

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

Отладка (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 параметр К: тип К);

THE BELL

Есть те, кто прочитали эту новость раньше вас.
Подпишитесь, чтобы получать статьи свежими.
Email
Имя
Фамилия
Как вы хотите читать The Bell
Без спама