Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программа ГЭ_спец_2012 ответы light.doc
Скачиваний:
31
Добавлен:
15.11.2019
Размер:
3.71 Mб
Скачать

Разработка структуры по при объектом подхода

Большинство классов можно отнести к определенному типу, который применительно к данному подходу называют стереотипам, например:

  • классы-сущности (классы предметной области);

  • граничные (интерфейсные) классы;

  • управляющие классы;

  • исключения и т. д.

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

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

Управляющие классы служат для моделирования последовательного по­ведения, заложенного в один или несколько вариантов использования.

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

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

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

  • объекты одного класса посылают сообщения объектам другого класса;

  • объекты одного класса обращаются к компонентам объектов другого;

  • объекты одного класса используют объекты другого в списке параметров методов и т. п.

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

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

  1. Определение отношений между объектами: диаграмма последовательностей действий – обозначение объектов и сообщений, синхронные и асинхронные сообщения, линии жизни объектов, активации объекта, уничтожение объекта, разрыв линии жизни; диаграмма кооперации (collaboration diagrams) – обозначение объектов и потоков данных, варианты реализации сценария.

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

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

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

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

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

Если объект создается сообщением, то его рисуют справа от стрелки со¬общения так, чтобы стрелка сообщения входила в него слева.

Диаграммы последовательностей также позволяют изображать парал¬лельные процессы. Асинхронные сообщения, которые не блокируют работу вызывающего объекта, показывают половинкой стрелки (рис. 7.7, а). Такие сообщения могут:

создавать новую ветвь процесса;

создавать новый объект (рис. 7.7,6);

устанавливать связь с уже выполняющейся ветвью процесса.

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

Уничтожение объекта показывают большим знаком «X» (рис. 7.7, г).

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

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

  1. Определение отношений между классами: ассоциация, обобщение, агрегация, композиция, направление ассоциации, абстрактные классы и методы, параметризованные классы, связывание классов, обозначение связывания; классы интерфейсы.

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

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

Композиция - более сильная разновидность агрегации, которая подразу¬мевает, что объект-часть может принадлежать только единственному целому. Объект-часть при этом создается и уничтожается только вместе со своим це¬лым.

Уточненные отношения между классами фиксируют на диаграмме клас¬сов. Для этого используют специальные уловные обозначения (рис. 7.11).

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

Специальное обозначение на диаграмме классов этапа проектирования используют для указания абстрактных классов и методов: на диаграмме классов их имена выделяют курсивом, либо перед именем класса указывают стереотип «abstract».

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

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

Особое место в процессе проектирования классов занимает проектиро¬вание интерфейсов.

Интерфейсы. Интерфейсам в UML называют класс, содержащий толь¬ко объявление операций.

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

На диаграмме классов интерфейс можно показать двумя способами: с помощью специального условного обозначения (рис. 7.13, а) или, объявив для класса стереотип «Interface» (рис. 7.13, б).

Реализацию интерфейса также можно показать двумя способами: сокра¬щенно или, используя отношение реализации.

Для остальных классов, ассоциированных с интерфейсом, следует уточнить ассоциацию, показав отношение зависимости. Это отношение в данном случае озна¬чает, что класс использует указан¬ный интерфейс, т. е. обращается к описанным в интер¬фейсе функциям.

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

  1. Проектирование классов: структура объектов – атрибуты и операции класса, полное описание атрибута, полное описание операции, ответственность класса; диаграмма состояний объекта (statechart diagrams); диаграмма деятельностей методов класса; диаграмма компонентов (component diagrams); диаграмма размещения (deployment diagrams).

Собственно проектирование классов предполагает окончательное опре¬деление структуры и поведения его объектов. Структура объектов опреде¬ляется совокупностью атрибутов и операций класса. Каждый атрибут - это поле или совокупность полей данных, содержащихся в объекте класса.

Поведение объектов класса определяется реализуемыми обязанностя¬ми. Обязанности выполняются посредством операций класса.

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

<признак видимости> <имя>:<тип>=<значение по умолчанию>,

где признак видимости может принимать одно из трех значений: «+» - об¬щий; «#» - защищенный; «-» - скрытый.

Полное описание операции на диаграмме класса в UML может выгля¬деть следующим образом:

<признак видимости><имя>(<список параметров>): <тип возвращаемого значения>.

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

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

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

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

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

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

Диаграммы состояний показывают состояния объекта, возможные пере¬ходы, а также события или сообщения, вызывающие каждый переход.

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

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

<Событие> [<Условие>]/<Действие>.

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

Условие записывается в виде логического выражения. Переход происхо¬дит, если результат выражения — «истина». Объект не может одновременно перейти в два разных состояния, поэтому условия перехода для любого со¬бытия должны быть взаимоисключающими.

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

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

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

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

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

Компоновка программных компонентов

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

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

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

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

Кроме этого, на диаграмме компонентов допустимо уточнять зависи¬мость между компонентами, используя обозначения обобщения, ассоциации, композиции, агрегатирования и реализации.

Проектирование размещения программных компонентов для распределенных программных систем

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

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

  1. Основные принципы и стадии тестирования; ручное тестирование – статический и динамический подход, методы ручного тестирования: тестирование исходного текста, сквозные просмотры, проверка за столом, оценки программ; стратегии тестирования: структурный подход – методы «белого» ящика, функциональный подход – методы «черного» ящика.

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

Три стадии тестирования, соответствующие завершению соответствующей части Системы:

• автономное тестирование компонентов программного обеспечения;

• комплексное тестирование разрабатываемого программного обеспечения;

• системное или оценочное тестирование на соответствие основным критериям качества.

Для повышения качества тестирования рекомендуется соблюдать основные принципы:

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

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

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

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

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

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

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

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

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

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

• программист рассказывает о логике работы программы и отвечает на ?-сы инспекторов;

• программа анализируется по списку ?-в для выявления исторически сложившихся общих ошибок программирования.

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

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

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

• участникам заседания предлагают несколько тестов;

• участники заседания мысленно выполняют каждый тест в соответствии с логикой программы, при этом состояние программы отслеживается на бумаге или доске;

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

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

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

Оценка программ (ОП). Этот метод непосредственно не связан с тестированием, но его использование также улучшает качество программирования. Его используют для анонимной ОП в терминах ее общего качества, простоты эксплуатации и ясности. Цель метода - обеспечить сравнительно объективную оценку и самооценку программистов. Такая оценка выполняется следующим образом. Выбирается программист, который должен выполнять обязанности администратора процесса. Он набирает группу 6-20 чел., кот. должны заниматься разработкой сходных программ. Каждому участнику предлагается представить для рассм. 2 программы, с его точки зрения - наилучшую и наихудшую. Отобранные программы случайным образом распределяются м/д участниками. Им дают по 4 программы - 2 наилучшие и 2 наихудшие, но не говорят, какие программы плохие, а какие - хорошие. Программист просматривает эти программы и заполняет анкету, в которой оценивает качество программ по семибальной шкале. После этого результаты оценки сверяют, а проверяющий дает общий комментарий и рекомендации по улучшению программ.

  1. Структурное тестирование (тестирование маршрутов) – критерии формирования тестовых наборов: покрытие операторов, покрытие решений (переходов), покрытие условий, покрытие решений/условий, комбинаторное покрытие условий.

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

СТ имеет ряд недостатков, т.к. тестовые наборы, построенные по данной стратегии:

• не обнаруживают пропущенных маршрутов;

• не обнаруживают ошибок, зависящих от обрабатываемых данных, например, в операторе if (a - b) < eps - пропуск функции абсолютного значения abs проявится только, если а<b;

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

Для формирования тестов программу представляют в виде графа, вершины которого соответствуют операторам программы, а дуги представляют возможные варианты передачи управления.

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

Procedure т (а, b: rеаl; var x: real);

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

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

Формирование тестовых наборов для тестирования маршрутов может осуществляться по нескольким критериям: покрытие операторов; покрытие решений (переходов); покрытие условий; покрытие решений/условий; комбинаторное покрытие условий.

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

Для фрагмента, алгоритм и граф которого представлены на рис. 9.2, можно было бы выполнить каждый оператор один раз, задав в качестве входных данных а=2, b=0, х=3. Но при этом из второго условия следует, что переменная х может принимать любое значение, и в некоторых версиях языка Pascal это значение проверяться не будет (!).

Кроме того:

• если при написании программы в первом условии будет указано: (а>1) or (b=0), то ошибка обнаружена не будет;

• если во втором условии вместо х>1 записать х>0, то эта ошибка тоже не будет обнаружена;

• существует путь 1-2-4-6 (см. рис. 9.2, б), в котором х вообще не меняется и, если здесь есть ошибка, она не будет обнаружена.

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

Покрытие решений (переходов). Для реализации этого критерия необходимо такое количество и состав тестов, чтобы результат проверки каждого условия (т.е. решение) принимал значения «истина» или «ложь», по крайней мере, один раз. Нетрудно видеть, что критерий покрытия решений удовлетворяет критерию покрытия операторов, но является более «сильным». Программу, алгоритм которой представлен на рис. 9.2, а, можно протестировать по методу покрытия решений двумя тестами, покрывающими либо пути: 1-2-4-6, 1-2-3-4-5-6, либо пути: 1-2-3-4-6, 1-2-4-5-6, напр.:

а=3, b=0, х=3— путь 1-2-3-4-5-6;

а=2, b=1, х=1 — путь 1-2-4-6.

Однако путь, где х не меняется, будет проверен с вероятностью 50 %: если во втором условии вместо условия х>1 записано х<1, то этими двумя тестами ошибка обнаружена не будет.

Покрытие условий. Критерий покрытия условий является еще более «сильным» по сравнению с предыдущими. В этом случае формируют некоторое количество тестов, достаточное для того, чтобы все возможные результаты каждого условия в решении были выполнены, по крайней мере, один раз. Но этот критерий не всегда приводит к выполнению каждого оператора, по крайней мере, один раз. К критерию требуется дополнение, заключающееся в том, что каждой точке входа управление должно быть передано, по крайней мере, один раз. Программа, алгоритм которой представлен на рис. 9.2а, проверяет четыре условия: 1) а>1; 2) b=0; 3) а=2; 4) х>1. Необходимо реализовать все возможные ситуации: а>1,а>=1, b=0, b<>0, а=2, а<>2, х>1,х<=1.

Тесты, удовлетворяющие этому условию:

а=2, b=0, х=4 — путь 1-2-3-4-5-6, условия: 1 - да, 2 - да, 3 - да, 4 - да;

а=1, b=1, х=1 — путь 1-2-4-6, условия: 1 - нет, 2 - нет, 3 - нет, 4 - нет.

Критерий покрытия условий часто удовлетворяет критерию покрытия решений, но не всегда.

Тесты критерия покрытия условий для ранее рассмотренных примеров покрывают результаты всех решений, но это случайное совпадение. Например, тесты:

а=1, b=0, х=3 — путь 1-2-3-6, условия: 1 - нет, 2 - да, 3 - нет, 4 - да;

а=2, b=1, х=1 — путь 1-2-3-4-5-6, условия: 1 - да, 2 - нет, 3 - да, 4 - нет

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

Основной недостаток метода - недостаточная чувствительность к ошибкам в логических выражениях.

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

Анализ, проведенный выше, показывает, что этому критерию удовлетворяют тесты:

а=2, b=0, х=4 — путь 1-2-3-4-5-6, условия: 1 - да, 2 - да, 3 - да, 4 - да;

а=1, b=1, х=1 — путь 1-2-4-6, условия; 1 - нет, 2 - нет, 3 - нет, 4 - нет.

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

1) а>1, b=0; 2) а>1, b<>0; 3) а<=1,b=0; 4) а<=1; b<>0; 5) а=2, х>1; 6) а=2, х<=1; 7) а<>2, х> 1; 8) а<>2, х<=1.

Эти комбинации можно проверить четырьмя тестами:

а=2, b=0, х=4 —комбинации (1), (5);

а=2, b=1, х=1 —комбинации (2), (6);

а=1, b=0, х=2 —комбинации (3), (7);

а=1, b=1, х=1 —комбинации (4), (8).

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

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

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

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

• передавать управление каждому оператору, по крайней мере, один раз.

Термин «возможных» употреблен здесь потому, что некоторые комбинации условий могут быть нереализуемы. Например, для комбинации k<0 и k>40 задать k невозможно.

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

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

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

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

• если некоторый параметр х может принимать значения в интервале [1, 999], то выделяют один правильный класс 1=х=999 и два неправильных х 1 и х999;

• если входное условие определяет диапазон значений порядкового типа, например, «в автомобиле могут ехать от 1 до 6 человек», то определяется один правильный КЭ и два неправильных ни 1 и более 6 человек;

• если входное условие описывает множество входных значений и есть основания полагать, что каждое значение трактуется особо, например, «типы графических файлов bmp, jpeg, vsd», то определяют правильный КЭ для каждого значения и один неправильный класс, например, txt;

• если входное условие описывает ситуацию «должно быть», например, «первым символом идентификатора д.б. буква», то определяется один правильный КЭ (первый символ - буква) и один неправильный (первый символ - не буква);

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

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

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

Анализ граничных значений (ГЗ). ГЗ - это значения на границах КЭ входных значений или около них. Анализ показывает, что в этих местах резко увеличивается возможность обнаружения ошибок. Например, если в программе анализа вида треугольника было записано А + В . С вместо А + В С, то задание граничных значений приведет к ошибке линия будет отнесена к одному из видов треугольника. Применение метода анализа ГЗ требует определенной степени творчества и специализации в рассматриваемой проблеме. Тем не менее, существует несколько общих правил для применения этого метода

• если входное условие описывает область значений, то следует построить тесты для границ области и тесты с неправильными входными данными для ситуаций незначительного выхода за границы области, например, если описана область [-1.0, +1.0], то должны быть сгенерированы тесты -1.0, + 1.0,-1.001 и+1.001;

• если входное условие удовлетворяет дискретному ряду значений, то следует построить тесты для минимального и максимального значений и тесты, содержащие значения большие и меньшие этих двух значений, например, если входной файл может содержать от 1 до 255 записей, то следует проверить 0, 1, 255 и 256 записей;

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

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

Помимо указанных ГЗ, целесообразно поискать другие. Анализ ГЗ, если он применен правильно, является одним из наиболее полезных методов проектирования тестов. Однако следует помнить, что ГЗ могут быть едва уловимы и определение их связано с большими трудностями, что является недостатком этого метода. Оба описанных метода основаны на исследовании входных данных. Они не позволяют проверять результаты, получаемые при различных сочетаниях данных. Для построения тестов, проверяющих сочетания данных, применяют методы, использующие булеву алгебру.

Анализ причинно-следственных связей (ПСС). Анализ ПСС позволяет системно выбирать высоко результативные тесты. Метод использует алгебру логики и оперирует понятиями «причина» и «следствие». Причиной в данном случае называют отдельное входное условие или КЭ. Следствием - выходное условие или преобразование системы. Идея метода заключается в отнесении всех следствий к причинам, т. е. в уточнении ППС. Данный метод дает полезный побочный эффект, позволяя обнаруживать неполноту и неоднозначность исходных спецификаций. Построение тестов осуществляют в несколько этапов. Сначала, поскольку таблицы ППС при применении метода к большим спецификациям становятся громоздкими, спецификации разбивают на «рабочие» участки, стараясь по возможности выделять в отдельные таблицы независимые группы ППС. Затем в спецификации определяют множество причин и следствий. Далее на основе анализа семантического (смыслового) содержания спецификации строят таблицу истинности, в которой каждой возможной комбинации причин ставится в соответствие следствие. При этом целесообразно истину обозначать «I», ложь - «О», а для обозначения безразличных состояний условий применять обозначение «X», которое предполагает произвольное значение условия (0 или 1). Таблицу сопровождают примечаниями, задающими ограничения и описывающими комбинации причин иили следствий, которые являются невозможными из-за синтаксических или внешних ограничений. При необходимости аналогично строится таблица истинности для КЭ. И, наконец, каждую строку таблицы преобразуют в тест. При этом рекомендуется по возможности совмещать тесты из независимых таблиц. Данный метод позволяет строить высоко результативные тесты и обнаруживать неполноту и неоднозначность исходных спецификаций. Его недостатком является неадекватное исследование ГЗ.

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

  1. Тестирование модулей: восходящее, нисходящее, комбинированное, модули-заглушки, тестирование специалистами–тестерами, документирование тестирования, регрессионное тестирование, комплексное тестирование, критерии завершения тестирования, оценочное - системное тестирование.

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

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

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

В этом случае автономно тестируется только основной модуль. При его тестировании все вызываемые им модули заменяют модулями, которые в той или иной степени имитируют поведение вызываемых модулей (рис. 9.4). Такие модули принято называть «заглушками». В отличие от тестирующих программ заглушки очень просты, например, они могут просто фиксировать, что им передано управление. Часто заглушки просто возвращают какие-либо фиксированные данные. Как только тестирование основного модуля завершено, к нему подключают модули, непосредственно им вызываемые, и необходимые заглушки, а затем проводят их совместное тестирование. Далее последовательно подключают следующие модули, пока не будет собрана вся система.

Основной недостаток НТ - отсутствие автономного тестирования модулей. Поскольку модуль получает данные не непосредственно, а через вызывающий модуль, то гораздо сложнее обеспечить его «достаточное» тестирование.

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

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

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

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

1 - ошибка кодирования - программа ведет себя не так, как следует из общепринятых представлений, например, 2+2=5 - на что разработчик может выдать резолюцию «соответствует проекту»; 2 - ошибка проектирования - программа ведет себя в соответствии с проектом, но специалист по тестированию не согласен с данным решением в проекте - на что разработчик может выдать резолюцию «не согласен с предложением»; 3 - предложение - предложение по улучшению проекта; 4 - расхождение с документацией - обнаружено, что программа ведет себя не так, как указано в документации; 5 - взаимодействие с аппаратурой - обнаружены проблемы при использовании определенного вида аппаратуры; 6 - вопрос - программа делает что-то не совсем понятное.

Описание проблемы должно быть коротким и понятным, например «Система не запоминает настройки принтера, выполняемые в окне настройки». Если программист исправляет ошибку, то тестирование повторяют сначала, так как при исправлении ошибки программист может внести в программу новые ошибки. Такое тестирование называют «регрессионным».

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

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

• основанные на методологиях проектирования тестов – определенное количество тестов, полученных по методам анализа ППС, анализа ГЗ и предположения об ошибке, перестают выявлять ошибки;

• основанные на оценке возможного количества ошибок - возможное количество ошибок оценивают экспертно, или по специальным методикам, а затем завершают тестирование при нахождении примерно 93-95% ошибок;

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

Часто тестирование завершают потому, что закончилось время, отведенное на выполнение данного этапа. В этом случае тестирование сворачивают, обходясь минимальным вариантом. Минимальное тестирование предполагает тестирование граничных значений; тщательную проверку руководства; тестирование минимальных конфигураций технических средств; тестирование возможности редактирования команд и повторения их в любой последовательности; тестирование устойчивости к ошибкам пользователя. Часть ошибок при этом остаются неисправленными «отложенными» до выпуска следующей версии.

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

Оценочное тестирование, которое также называют «тестированием системы в целом», включает следующие виды

• тестирование удобства использования - последовательная проверка соответствия программного продукта и документации на него основным положениям технического задания;

• тестирование на предельных объемах - проверка работоспособности программы на максимально больших объемах данных, например, объемах текстов, таблиц, большом количестве файлов и т. п.;

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

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

• тестирование защиты - проверка защиты, например, от несанкционированного доступа к информации;

• тестирование производительности - определение пропускной способности при заданной конфигурации и нагрузке;

• тестирование требований к памяти - определение реальных потребностей в оперативной и внешней памяти;

• тестирование конфигурации оборудования - проверка работоспособности программного обеспечения на разном оборудовании;

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

• тестирование удобства установки - проверка удобства установки;

• тестирование надежности - проверка надежности с использованием соответствующих математических моделей;

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

• тестирование удобства обслуживания - проверка средств обслуживания, включенных в программное обеспечение;

• тестирование документации - тщательная проверка документации, например, если документация содержит примеры, то их все необходимо попробовать;

• тестирование процедуры - проверка ручных процессов, предполагаемых в системе.

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

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

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

Классификация ошибок

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

В целом сложность отладки обусловлена следующими причинами:

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

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

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

• отсутствуют четко сформулированные методики отладки.

В соответствии с этапом обработки, на котором проявляются ошибки, различают:

синтаксические ошибки - фиксируемые компилятором (транслятором, интерпретатором) при выполнении синтаксического и частично семантического анализа программы;

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

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

Синтаксические ошибки относят к группе самых простых, так как синтаксис языка, как правило, строго формализован, и ошибки сопровождаются развернутым комментарием с указанием ее местоположения. Определение причин таких ошибок, как правило, труда не составляет, и даже при нечетком знании правил языка за несколько прогонов удается удалить все ошибки данного типа. Следует иметь в виду, что чем лучше формализованы правила синтаксиса языка, тем больше ошибок из общего количества может обнаружить компилятор и, соответственно, меньше ошибок будет обнаруживаться на следующих этапах. В связи с этим говорят о языках программирования с защищенным синтаксисом и с незащищенным синтаксисом. К первым, безусловно, можно отнести Pascal, имеющий очень простой и четко определенный синтаксис, хорошо проверяемый при компиляции программы, ко вторым - Си со всеми его модификациями. Чего стоит хотя бы возможность выполнения присваивания в условном операторе в Си, например: if (c = n) x = 0; /* в данном случае не проверятся равенство с и n, а выполняется присваивание с значения n, после чего результат операции сравнивается с нулем, если программист хотел выполнить не присваивание, а сравнение, то эта ошибка будет обнаружена только на этапе выполнения при получении результатов, отличающихся от ожидаемых */

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

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

• появление сообщения об ошибке, зафиксированной схемами контроля выполнения машинных команд, например, переполнении разрядной сетки, ситуации «деление на ноль», нарушении адресации и т. п.;

• появление сообщения об ошибке, обнаруженной операционной системой, например, нарушении защиты памяти, попытке записи на устройства, защищенные от записи, отсутствии файла с заданным именем и т. п.;

• «зависание» компьютера, как простое, когда удается завершить программу без перезагрузки операционной системы, так и «тяжелое», когда для продолжения работы необходима перезагрузка;

• несовпадение полученных результатов с ожидаемыми.

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

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

Логические ошибки имеют разную природу. Так они могут следовать из ошибок, допущенных при проектировании, напр., при выборе методов, разработке алгоритмов или определении структуры классов, а могут быть непосредственно внесены при кодировании модуля.

К последней группе относят:

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

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

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

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

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

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

- опосредованного проявления ошибок;

- возможности взаимовлияния ошибок;

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

- отсутствия повторяемости проявлений некоторых ошибок от запуска к запуску – так называемые стохастические ошибки;

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

- написания отдельных частей программы разными программистами.

Методы отладки ПО

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

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

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

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

Метод дедукции. По методу дедукции вначале формируют множество причин, которые могли бы вызвать данное проявление ошибки. Затем, анализируя причины, исключают те, которые противоречат имеющимся данным. Если все причины исключены, то следует выполнить дополнительное тестирование исследуемого фрагмента. В противном случае наиболее вероятную гипотезу пытаются доказать. Если гипотеза объясняет полученные признаки ошибки, то ошибка найдена, иначе - проверяют следующую причину (рис. 10.4).

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

Методы и средства получения дополнительной информации

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

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

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

Интегрированные средства отладки. Большинство современных сред программирования (Delphi, C++, Visual Studio и т. д.) включают средства отладки, которые обеспечивают максимально эффективную отладку. Они позволяют:

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

• предусматривать точки останова;

• выполнять программу до оператора, указанного курсором;

• отображать содержимое любых переменных при пошаговом выполнении;

• отслеживать поток сообщений и т. п.

Применять интегрированные средства в рамках среды достаточно просто. Используют разные приемы в зависимости от проявлений ошибки. Если получено сообщение об ошибке, то сначала уточняют, при выполнении какого оператора программы оно получено. Для этого устанавливают точку останова в начало фрагмента, в котором проявляется ошибка, и выполняют операторы в пошаговом режиме до проявления ошибки. Аналогично поступают при «зависании» компьютера. Если получены неправильные результаты, то локализовать ошибку обычно существенно сложнее. В этом случае сначала определяют фрагмент, при выполнении которого получаются неправильные результаты. Для этого последовательно проверяют интересующие значения в узловых точках. Обнаружив значения, отличающиеся от ожидаемых, по шагам трассируют соответствующий фрагмент до выявления оператора, выполнение которого дает неверный результат. Для уточнения природы ошибки возможен анализ машинных кодов, флагов и представления программы и значений памяти в 16-ричном виде. Причину ошибки определяют, используя один из

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

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

Общая методика отладки программного обеспечения

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

2 этап - локализация ошибки - определение конкретного фрагмента, при выполнении которого произошло отклонение от предполагаемого вычислительного процесса. Локализация может выполняться:

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

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

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

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

4 этап - исправление ошибки - внесение соответствующих изменений во все операторы, совместное выполнение которых привело к ошибке.

5 этап - повторное тестирование - повторение всех тестов с начала, так как при исправлении обнаруженных ошибок часто вносят в программу новые.

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

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

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

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

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

  1. Цель испытаний, виды испытаний в жизненном цикле ПО - опытного образца, рабочей версии, модернизированной версии; категории испытаний - функциональные, стрессовые, использования ресурсов ЭВМ, параллельного решения задач; испытания программ на надежность - прямые экспериментальные методы определения показателей надежности программ в условиях нормального функционирования, форсированные методы испытаний реальных систем на надежность; достоверность испытаний - методическая и статистическая достоверность; документирование результатов испытаний - исходные и отчетные документы при испытаниях программ: техническое задание, государственные и отраслевые стандарты, программа испытаний, методики испытаний, протоколы испытаний, акт испытаний.

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

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

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

Испытания таких программ, как системы реального времени, операционные системы и программы управления данными, которые сохраняют «память» о предыдущих входных данных, особенно трудны.

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

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

В соответствии с ГОСТ 16504—81 под испытанием промышленной продук-ции понимают экспериментальное определение количественных и/или качественных характеристик объекта испытания как результата воздействия на него; при его функ-ционировании; при моделировании объекта и/или воздействия. Под испытанием про-граммной продукции следует понимать экспериментальное определение количест-венных и/или качественных характеристик свойств продукции при ее функциониро-вании в реальной среде и/или моделировании среды функционирования.

Целью испытания является экспериментальное определение фактических (достигнутых) характеристик свойств испытываемого ПС и определение степени со-ответствия созданного комплекса программ техниче¬скому заданию, полученному от заказчика. Эти характеристики могут быть как количественными, так и качественны-ми. Важно, чтобы на их основе можно было сделать вывод о пригодности данного ПС к использованию по своему назначению. Если вывод отрицательный, то образец ПС возвращается на доработку. Таким образом, перекрывается доступ недоброкачест-венной продукции к пользователю, Непосредственно в ходе испытаний качество ПС может и не измениться, так как локализация ошибок не является целью испытания. Вместе с тем некоторые дефекты в программах и документации могут устраняться по ходу испытания [11].

Методики проведения испытаний

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

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

2. Анализируют множество ситуаций, которые могут возникнуть при функцио-нировании ПС. Выбирают наиболее характерные ситуации. Каждую из них выражают через тестовый набор входных данных. Далее сущность испытания и анализа результатов сводится к подходу 1;

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

4. ПС испытывают в реальной среде функционирования;

5. ПС испытывают в статистически моделируемой среде функционирования, адекватной реальной среде.

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

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

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

Анализ показывает, что абсолютная проверка ПС ни при одном из рассмот-ренных подходов не осуществима. Поэтому при планировании испытаний необходи-мо предварительно анализировать структуры испытываемых программ и входных данных. В частности, следует устанавливать те пути граф-схемы программы, исполь-зование которых при преобразовании данных наиболее вероятно. Эта задача анало-гична подходам 1 и 2. Для сложных программных комплексов она не имеет строго математического решения. Вместе с тем на практике нередко удается заранее устано-вить наиболее вероятные ситуации, которые могут возникнуть в автоматизируемой системе, а, следовательно, и наборы входных данных, описывающие эти ситуации.

Методика решения задачи планирования испытания включает в себя сле-дующие этапы:

— нахождение всех путей реализации;

— выделение минимального подмножества путей, обеспечивающих проверку всех участков программы;

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

Особенности испытаний на надежность программ

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

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

При испытаниях ПС на надежность функционирования необ¬ходимо разделять причины отказов и отказовых ситуаций на обусловленные ненадежностью аппарату-ры и ошибками в прог¬раммах. Устойчивые отказы аппаратуры селектируются доста¬точно просто. Однако кратковременные сбои в аппаратуре и последствия ошибок в программе требуют тщательного анализа для выделения и диагностики их источника. Значительную по¬мощь может оказать программа анализа сбоев. Эта программа авто-матически регистрирует наличие отказа и отказовой ситуации, а также условия их возникновения, осуществля¬ет первичный анализ и классификацию возможных источ-ников аномалий функционирования. Для диагностики и локализации причин отказа обычно требуется дополнительное стохастическое и детерминированное тестирова-ние, которое позволяет либо вы¬делить первичную ошибку в программе, либо отнести источник отказа к сбою в аппаратуре. При дополнительном тестирова¬нии одна из за-дач заключается в подготовке стохастических тестов, способных значительно повы-сить частоту проявления отказов вследствие ошибок. Это позволяет в конце концов за¬фиксировать значения тестовых данных, при которых происходит отказ, и детерми-нированным тестированием локализовать ошибку [1].

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

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

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

Особым видом форсированных испытаний является тестиро¬вание эффектив-ности средств контроля и восстановления прог¬рамм, данных и вычислительного про-цесса. Для этого имитиру¬ются запланированные экстремальные условия функциони-рова¬ния программ, при которых в наибольшей степени вызываются средства про-граммного рестарта. При таких испытаниях основ¬ная задача состоит в проверке каче-ства функционирования средств повышения надежности, а оценка интегральных по-каза¬телей надежности отходит на второй план [13].

Исходные и отчетные документы при испытаниях программ.

Совместные испытания проводятся комиссией заказчика, в кото¬рой участ-вуют главный конструктор разработки и некоторые ведущие разработчики. Комиссия при испытаниях руководствует¬ся следующими документами:

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

2. действующими государственными и отраслевыми стандартами на проектиро-вание и испытания программ и на техническую документацию;

3. программой испытаний по всем требованиям технического за¬дания;

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

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

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

— объект испытаний, его назначение и перечень основных до¬кументов, опреде-ливших его разработку;

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

— собственно программу испытаний, содержащую проверку комплектности спроектированного ПС в соответствии с техни¬ческим заданием и план тес-тирования для проверки функциони¬рования программ по всем разделам тех-нического задания и до¬полнительным требованиям, формализованным от-дельными ре¬шениями;

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

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

Результаты испытаний фиксируются в протоколах, которые обычно содержат следующие разделы:

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

— указание методик, в соответствии с которыми проводились испытания, обра-ботка и оценка результатов;

— условия проведения тестирования и характеристика исходных данных;

— обобщенные результаты испытаний с оценкой их на соответ¬ствие требова-ниям технического задания и другим руководящим документам;

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

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

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

Сертификационные испытания

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

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

Использование сертифицированных ПС стало весьма актуальным. Работа во мно-гих сферах уже невозможна без применения компьютерной техники и использования спе-циализированных прикладных программ. Ведомственные интересы требуют усиления кон-троля за качеством ПС, обеспечением их высоких потребительских свойств, эффективно-стью затрат на их разработку, эксплуатацию, сопровождение. Именно в связи с этим, а так-же в целях защиты пользователей программных средств от недобросовестных и непрофес-сиональных разработчиков создаются испытательные лаборатории программных средств, получающие аккредитацию в Системе сертификации ГОСТ Р (аттестат аккредитации РОСС RU.0001.22СП29). Область аккредитации лабораторий - программные средства (код ОПС 50 1000 - 50 9000). Сертификация ПС проводится в рамках Системы сертификации электро-оборудования, созданной еще в 1992 г. и предусматривающей для конкретных видов про-дукции добровольную или обязательную сертификацию. Правила проведения сертифика-ции электрооборудования зарегистрированы в Минюсте России 2 сентября 1999 г. (регист-рационный № 1885) и в Государственном реестре 21 сентября 1999 г. (регистрационный № РОСС RU.0001.01MЛ00). Для ПС проводится добровольная сертификация с использовани-ем схемы сертификации № 3 [14].

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

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

Проводится проверка соответствия ПС требованиям таких государственных стан-дартов, как ГОСТ Р ИСО/МЭК 9126-93 "Информационная технология. Оценка программ-ной продукции. Характеристики качества и руководства по их применению", ГОСТ Р ИСО/МЭК ТО 9294-93 "Информационная технология. Руководство по управлению доку-ментированием программного обеспечения", ГОСТ Р ИСО 9127-94 "Системы обработки информации. Документация пользователя и информация на упаковке для потребительских программных пакетов", ГОСТ 28195-89 "Оценка качества программных средств. Общие по-ложения", ГОСТ 28806-90 "Качество программных средств. Термины и определения" [11].

Сертификационные испытания проводятся лабораторией только на лицензионном системном программном обеспечении с применением инструментальных средств тестиро-вания. Инспекционный контроль сертифицированных ПС проводится органом по сертифи-кации "Сертинформ ВНИИНМАШ" не реже одного раза в год. Наряду с этим отмечаются случаи представления на испытания ПС с недооформленной программной и эксплуатаци-онной документацией, без контрольных примеров. Не полностью сформированные ком-плекты файлов ПС, направленных на сертификацию, не позволяют иногда даже инсталли-ровать эти программы.

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

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

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

Аттестационные испытания программных средств

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

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

Известны следующие виды испытаний ПС, проводимых с целью аттестации ПС:

испытания компонент ПС;

— системные испытания;

— приемо-сдаточные испытания;

— полевые испытания;

— промышленные испытания.

Испытания компонент ПС - это проверка (тестирование) работоспособности от-дельных подсистем ПС. Проводятся только в исключительных случаях по специальному решению аттестационной комиссии.

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

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

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

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

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

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

2. обработка программ и документации ПС специальными программными инструмен-тами (процессорами);

3. тестирование программ ПС;

4. экспертная оценка на основании изучения программ и документации ПС.

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

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

Для оценки некоторых примитивов качества ПС используется тестирование. К та-ким примитивам относится прежде всего завершенность ПС, а также его точность, устойчи-вость, защищенность и другие примитивы качества. В ряде случаев для оценки отдельных примитивов качества ПС тестирование применяется в сочетании с другими методами. Так для оценки качества документации по применению ПС (П-документированности) тестиро-вание применяется в сочетании с экспертной оценкой этой документации. Если при ком-плексной отладке ПС было проведено достаточно полное тестирование, то эти же тесты мо-гут быть использованы и при аттестации ПС. В этом случае аттестационная комиссия мо-жет воспользоваться протоколами тестирования, проведенного при комплексной отладки. Однако и в этом случае необходимо выполнить какие-либо новые тесты или хотя бы по-вторно некоторые старые. Если же тестирование при комплексной отладке будет признано недостаточно полным, то необходимо провести более полное тестирование. В этом случае может быть принято решение о проведении испытаний компонент или системных испыта-ний ПС, а также о возврате ПС разработчикам на доработку. Весьма важно, чтобы для оценки ПС по критерию легкости применения было проведено (во время отладки и аттеста-ции ПС) полное тестирование по тестам, подготовленным на основании документации по применению, а по критерию сопровождаемости - по тестам, подготовленным по каждому из документов, предлагаемых для сопровождения ПС [2].

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

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

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

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

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

Рассмотрим пример.

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

1. начало работы;

2. коллектив сформирован, рабочие места подготовлены;

3. проектирование завершено;

4. программирование завершено;

5. комплексная отладка завершена;

6. оборудование закуплено;

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

8. то же для ПО, разработка проектной документации завершена;

9. группа технических писателей получила всю необходимую информацию об интерфейсах с пользователем, разработка программной документации завершена;

10. группа оценки качества (Quality Assurance – QA) разработала тесты;

11. группа QA оценила проект положительно;

12. группа QA завершила автономное тестирование;

13. группа QA завершила комплексное тестирование, получила всю документацию и действующий вариант системы;

14. проверка качества (проблемам качества будет посвящена отдельная лекция) завершена;

15. конец работы (конечно, это не конец, будет еще сопровождение, но пример-то надо закончить).

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

Критическими путями являются пути 1-6-2-3-4-5-9-13-14-15 и 1-6-2-3-4-5-12-13-14-15, т.е. вся работа не может быть выполнена быстрее, чем за двадцать одну неделю. Понятно, что с точки зрения оптимальной загрузки коллектива было бы лучше, чтобы все пути в графе от начала к концу имели примерно одинаковую длительность с тем чтобы как-то уменьшить длину критического пути. Например, есть соблазн заставить группу QA проводить даже начальное тестирование, уменьшив нагрузку на программистов, работа которых находится на критическом пути. Но тогда очень трудно определить границы ответственности, программисты начинают выдавать откровенную халтуру и в результате сроки даже удлиняются. В реальных проектах, где работ очень много, все-таки удается путем перераспределения работ улучшать сетевой график, по крайней мере, к этому стремятся все руководители.

Еще несколько замечаний по данному примеру. Явно неудачно спланированы работы между событиями 1, 2, 6. Коллектив сформирован за одну неделю, а рабочие места еще не готовы. Группа технических писателей начинает работать на шесть недель позже проектировщиков, а группа QA имеет трехнедельный перерыв перед завершением проектирования и т.д.

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

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

Для сравнения с сетевым графиком нарисуем диаграмму Ганта для того же примера:

Если в сетевом графике особенно наглядно видны зависимости работ друг от друга, (например, работа 12-13 может начаться только после завершения работ 5-12 и 11-12), то в диаграмме Ганта основной упор делается на то, что происходит в каждую конкретную неделю, например, видно, что группа QA имеет перерыв в работе в 2 недели между работами 11-12 (автономное тестирование) и 12-13 (комплексное тестирование). Именно поэтому "большие начальники" предпочитают диаграммы Ганта: в конце каждой недели проводишь вертикальную линию и сразу видишь, какие работы велись, что должно кончиться, а что начаться. Должен признаться, что я и сам нашел пару ошибок в расчетах по сетевому графику, пока строил диаграмму Ганта для этого примера. Тем самым я еще раз убедился, что диаграмма Ганта нагляднее сетевого графика, или в том, что я уже большой начальник, а не технический специалист. Технические менеджеры предпочитают сетевые графики, так как им важнее информация о том, что от чего зависит, да и пересчитывать критические пути им приходится практически каждую неделю.

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

  1. Сборочное программирование, основы компонентной объектной модели (COM): организация интерфейса COM, базовый интерфейс COM-IUnknown, серверы COM-объектов, создание и повторное использование COM-объектов, маршалинг и демаршалинг.

Основы компонентной объектной модели

Компонентная объектная модель (СОМ) – фундамент компонентно-ориентированных средств для всего семейства операционных систем Windows. СОМ определяет стандартный механизм, с помощью которого одна часть программного обеспечения предоставляет свои услуги другой части. Общая архитектура предоставления услуг в библиотеках, приложениях, системном и сетевом ПО позволяет СОМ изменить подход к созданию программ. СОМ устанавливает понятия и правила, необходимые для определения объектов и интерфейсов; кроме того, в ее состав входят программы, реализующие ключевые функции.

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

Объект СОМ всегда реализуется внутри некоторого сервера. Сервер может быть либо DLL, подгружаемой во время работы приложения, либо отдельным самостоятельным процессом (ЕХЕ).

Для вызова операций интерфейса клиент объекта СОМ должен получить указатель на его интерфейс. Клиенту требуется отдельный указатель для каждого интерфейса, операции которого он намерен вызывать.

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

Благодаря СОМ клиентам нет нужды учитывать эти отличия – доступ ко всему осуществляется единообразно. Другими словами, в СОМ для доступа к услугам, предоставляемым любыми типами ПО, используется одна общая модель.

Организация интерфейса СОМ

Каждый интерфейс объекта СОМ – контракт между этим объектом и его клиентами. Они обязуются объект – поддерживать операции интерфейса в точном соответствии с его определениями, а клиент – корректно вызывать операции. Для обеспечения контракта надо задать

- идентификацию каждого интерфейса;

- описание операций интерфейса;

- реализацию интерфейса

Идентификация интерфейса

У каждого интерфейса СОМ два имени. Простое, символьное имя предназначено для людей, оно не уникально. Другое, сложное имя предназначено для использования программами. Программное имя уникально, оно позволяет точно идентифицировать интерфейс. Оно образуется с помощью глобального уникального идентификатора (GUID) – 16-байтовой величины, генерируемой автоматически. Уникальность во времени достигается за счет включения в каждый GUID метки времени, указателя момента создания, в пространстве – цифровыми параметрами компа, который использовался для генерации GUID.

Описание интерфейса – Орлов, 268-269.

Реализация интерфейса

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

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

- с помощью указателя на виртуальную таблицу извлекается указатель на требуемую операцию интерфейса;

- указатель на операцию обеспечивает доступ к ее реализации;

- исполнение кода операции обеспечивает требуемую услугу.

IUnknown – базовый интерфейс СОМ

Интерфейс IUnknown обеспечивает минимальное снаряжение каждого объекта СОМ. Он содержит 3 операции и предоставляет любому объекту СОМ 2 функциональные возможности

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

- операция AddRef( ) и Release( ) обеспечивают механизм управления времени жизни объекта.

Свой первый указатель на интерфейс объекта клиент получит при создании объекта СОМ. Для получения других указателей на интерфейсы в качестве параметра операции QueryInterface() задается идентификатор требуемого интерфейса (IID). Если требуемый интерфейс отсутствует, операция возвращает значениe NULL.

Имеет смысл отметить и второе важное достоинство операции QueryInterface. В сочетании с требованиями неизменности COM-интерфейсов она позволяет «убить двух зайцев»

- развивать компоненты;

- обеспечивать стабильность клиентов, использующих компоненты;

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

СОМ-объект должен сам себя уничтожить. Возникает вопрос – когда Когда он перестанет быть нужным всем своим клиентам, когда вытечет песок из часов его жизни. Роль песочных часов играет счетчик ссылок (СЧС) СОМ-объекта.

Правила финализации СОМ-объекта очень просты

- при выдаче клиенту указателя на интерфейс выполняется СЧС+1;

- при вызове операции AddRef выполняется СЧС+1;

- при вызове операции Release выполняется СЧС-1;

- при СЧС=0 объект уничтожает себя.

Конечно, клиент должен помогать достойному харакири объекта-самурая

- при получении от другого клиента указателя на интерфейс СОМ-объекта он должен вызвать в этом объекте операцию AddRef;

- в конце работы с объектом он обязан вызвать его операцию Release.

Серверы СОМ-объектов.

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

- Сервер «в процессе»(in-process) – объекты находятся в динамически подключаемой библиотеке, и, следовательно, выполняются в том же процессе, что и клиент;

- Локальный сервер(out-process) – объекты находятся в отдельном процессе, выполняющемся на том же компьютере, что и клиент;

Удаленный сервер – объекты находятся в DLL или в отдельном процессе, которые расположены на удаленном от клиента компьютере.

С точки зрения логики, клиенту безразлично, в сервере какого типа находится СОМ-объект – создание объекта, получение указателя на его интерфейсы, вызов его операций и финализации выполняются всегда одинаково. Хотя временные затраты на организацию взаимодействия в каждом из трех случаев, конечно, отличаются друг от друга.

Преимущество СОМ.

В качестве кратких выводов отметим основные преимущества СОМ.

1. СОМ обеспечивает удобный способ фиксации услуг, предоставляемых разными фрагментами ПО.

2. Общий подход к созданию всех типов программных услуг в СОМ упрощает проблемы разработки.

3. СОМ безразличен язык программирования, на котором пишутся СОМ-объекты и клиенты.

4. СОМ обеспечивает эффективное управление изменением программ – замену текущей версии компонента на новую версию с дополнительными возможностями.

Создание СОМ-объектов.

Создание СОМ-объекта базируется на использовании функций библиотеки СОМ.

Библиотека СОМ

- содержит функции, предлагающие базовые услуги объектам и их клиентам;

- предоставляет клиентам возможность запуска серверов СОМ-объектов.

Доступ к услугам библиотеки СОМ выполняется с помощью вызовов обычных функций. Чаще всего имена функций библиотеки СОМ начинаются с префикса «Со».

Для создания СОМ-объекта клиент вызывает функцию библиотеки СОМ CoCreateInstance. В качестве параметров этой функции посылаются идентификатор класса объекта CLSID и IDD интерфейса, поддерживаемого объектом. С помощью CLSID библиотека ищет сервер класса ( это делает диспетчер управления сервисами SCM – Service Control Manager). Поиск производится в системном реестре (Registry), отображающем CLSID в адрес исполняемого кода сервера. В системном реестре должны быть зарегистрированы классы СОМ-объектов.

Закончив поиск, библиотека СОМ запускает сервер класса.

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

В более общем случае клиент может создать несколько СОМ-объектов одного и того же класса. Для этого клиент использует фабрику класса (class factory) – СОМ-объект, способный генерировать объекты одного конкретного класса.

Очень часто возникает следующая ситуация – существующий СОМ-класс заменили другим, поддерживающим как старые, так и дополнительные интерфейсы и имеющим другой CLSID. Появляется задача – обеспечивать использование нового СОМ-класса старыми клиентами. Обычным решением является запись в системный реестр соответствия запись в системный реестр соответствия между старым и новым CLSID. Запись выполняется с помощью библиотечной функции CoTreatClass CoTreatAsClass (старый CLSID, новый CLSID).

Повторное использование СОМ-объектов

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

СОМ не поддерживает это средство.

Сом предлагает другие средства повторного использования – включение и агрегирование.

Применяются следующие термины

- внутренний объект – это базовый объект;

- внешний объект – это объект, повторно использующий услуги внутреннего объекта.

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

Маршалинг

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

Код посредника и заглушки автоматически генерируется компилятором MIDL (Microsoft IDL) по IDL-описанию интерфейса.