ОПИ-2. Министерство науки и образования рф
Скачать 1.52 Mb.
|
ТЕМА 5.МОДЕЛИ КАЧЕСТВА ПРОЦЕССОВ КОНСТРУИРОВАНИЯ В современных условиях, условиях жесткой конкуренции, очень важно гарантировать высокое качество вашего процесса конструирования ПО. Такую гарантию дает сертификат качества процесса, подтверждающий его соответствие принятым международным стандартам. Каждый такой стандарт фиксирует свою модель обеспечения качества. Наиболее авторитетны модели стандартов ISO 9001:2000, ISO / IЕС 15504 и модель зрелости процесса конструирования ПО (Capability Maturity Model - СММ) Института программной инженерии при американском университете Карнеги-Меллон. Модель стандарта ISO 9001:2000 ориентирована на процессы разработки из любых областей человеческой деятельности. Стандарт ISO/IЕС 15504 специализируется на процессах программной разработки и отличается более высоким уровнем детализации. Достаточно сказать, что объем этого стандарта превышает 500 страниц. Значительная часть идей ISO/IЕС 15504 взята из модели СММ. Базовым понятием модели СММ считается зрелость компании. Незрелой называют компанию, где процесс конструирования ПО и принимаемые решения зависят только от таланта конкретных разработчиков. Как следствие, здесь высока вероятность превышения бюджета или срыва сроков окончания проекта. Напротив, в зрелой компании работают ясные процедуры управления проектами и построения программных продуктов. По мере необходимости эти процедуры уточняются и развиваются. Оценки длительности и затрат разработки точны, основываются на накопленном опыте. Кроме того, в компании имеются и действуют корпоративные стандарты на процессы взаимодействия с заказчиком, процессы анализа, проектирования, программирования, тестирования и внедрения программных продуктов. Все это создает среду, обеспечивающую качественную разработку программного обеспечения. Таким образом, модель СММ фиксирует критерии для оценки зрелости компании и предлагает рецепты для улучшения существующих в ней процессов. Иными словами, в ней не только сформулированы условия, необходимые для достижения минимальной организованности процесса, но и даются рекомендации по дальнейшему совершенствованию процессов. Очень важно отметить, что модель СММ ориентирована на построение системы постоянного улучшения процессов. В ней зафиксированы пять уровней зрелости (рис.5) и предусмотрен плавный, поэтапный подход к совершенствованию процессов - можно поэтапно получать подтверждения об улучшении процессов после каждого уровня зрелости. Рис. 4. Пять уровней зрелости модели СММ Начальный уровень (уровень 1) означает, что процесс в компании не формализован. Он не может строго планироваться и отслеживаться, его успех носит случайный характер. Результат работы целиком и полностью зависит от личных качеств отдельных сотрудников. При увольнении таких сотрудников проект останавливается. Для перехода на повторяемый уровень (уровень 2) необходимо внедрить формальные процедуры для выполнения основных элементов процесса конструирования. Результаты выполнения процесса соответствуют заданным требованиям и стандартам. Основное отличие от уровня 1 состоит в том, что выполнение процесса планируется и контролируется. Применяемые средства планирования и управления дают возможность повторения ранее достигнутых успехов. Следующий, определенный уровень (уровень 3) требует, чтобы все элементы процесса были определены, стандартизованы и документированы. Основное отличие от уровня 2 заключается в том, что элементы процесса уровня 3 планируются и управляются на основе единого стандарта компании. Качество разрабатываемого ПО уже не зависит от способностей отдельных личностей. Уровень 5. Оптимизирующий Планомерное улучшение и повышение качества процесса Уровень 4. Управляемый Количественное управление процессом, его качеством Уровень 3. Определенный Процесс полностью определен и организован на основе единого стандарта компании Уровень 2. Повторяемый Процесс планируется и отслеживается Уровень 1. Начальный Самоорганизующийся хаос. Процесс осуществляется случайным образом С переходом на управляемый уровень (уровень 4) в компании принимаются количественные показатели качества как программных продуктов, так и процесса. Это обеспечивает более точное планирование проекта и контроль качества его результатов. Основное отличие от уровня 3 состоит в более объективной, количественной оценке продукта и процесса. Высший, оптимизирующий уровень (уровень 5) подразумевает, что главной задачей компании становится постоянное улучшение и повышение эффективности существующих процессов, ввод новых технологий. Основное отличие от уровня 4 заключается в том, что технология создания и сопровождения программных продуктов планомерно и последовательно совершенствуется. Каждый уровень СММ характеризуется областью ключевых процессов (ОКП), причем считается, что каждый последующий уровень включает в себя все характеристики предыдущих уровней. Иначе говоря, для 3-го уровня зрелости рассматриваются ОКП 3-го уровня, ОКП 2-го уровня и ОКП 1-го уровня. Область ключевых процессов образуют процессы, которые при совместном выполнении приводят к достижению определенного набора целей. Например, ОКП 5-го уровня образуют процессы: предотвращения дефектов; управления изменениями технологии; управления изменениями процесса. Если все цели ОКП достигнуты, компании присваивается сертификат данного уровня зрелости. Если хотя бы одна цель не достигнута, то компания не может соответствовать данному уровню СММ. Тема 6. ПРОЕКТИРОВАНИЕ ПО Определение метода и технологии. Требования к технологии. Стандарт проектирования. Стандарт оформления проектной документации. Стандарт интерфейса конечного пользователя с системой. ОПРЕДЕЛЕНИЕ МЕТОДА И ТЕХНОЛОГИИ Метод проектирования ПО представляет собой организованную совокупность процессов создания ряда моделей, которые описывают различные аспекты разрабатываемой системы с использованием четко определенной нотации. На более формальном уровне метод определяется как совокупность составляющих: Концепций и теоретических основ. В качестве таких основ могут выступать структурный или объектно-ориентированный подход. Нотаций, используемых для построения моделей статической структуры и динамики поведения проектируемой системы. В качестве таких нотаций обычно используются графические диаграммы, поскольку они наиболее наглядны и просты в восприятии (диаграммы потоков данных, и диаграммы «сущность – связь» для структурного подхода, диаграммы вариантов использования, диаграммы классов и др. – для объектно-ориентированного подхода. Процедур, определяющих практическое применение метода (последовательность и правила построения моделей, критерии, используемые для оценки результатов). Методы реализуются через конкретные технологии и поддерживающие их методики, стандарты и инструментальные средства, которые обеспечивают выполнение процессов ЖЦ ПО. Технология проектирования определяется как совокупность технологических операций проектирования в их последовательности и взаимосвязи, приводящая к разработке проекта ПО. ТРЕБОВАНИЯ К ТЕХНОЛОГИИ Современная технология проектирования должна обеспечивать: 1. Соответствие стандарту ISO/IEC 12207: 1995 (поддержка всех процессов ЖЦ ПО). 2. Гарантированное достижение целей разработки ЭИС в рамках установленного бюджета, с заданным качеством и в установленное время. 3. Возможность декомпозиции проекта на составные части, разрабатываемые группами исполнителей ограниченной численности (3-7 чел.), с последующей интеграцией составных частей. 4. Минимальное время получения работоспособного ПО ЭИС. Речь идет не о сроках готовности всей ЭИС, а о сроках реализации отдельных подсистем. Практика показывает, что даже при наличии полностью завершенного проекта внедрение ЭИС идет последовательно по отдельным подсистемам. 5. Независимость получаемых проектных решений от средств реализации ЭИС (СУБД, ОС, языков и систем программирования). 6. Поддержка комплексом согласованных CASE – средств, обеспечивающих автоматизацию процессов, выполняемых на всех стадиях ЖЦ ПО. Реальное применение любой технологии проектирования ПО ЭИС в конкретной организации и конкретном проекте невозможно без выработки ряда стандартов (правил, соглашений), которые должны соблюдаться всеми участниками проекта. К таким стандартам относятся: 1. Стандарт проектирования. 2. Стандарт оформления проектной документации. 3. Стандарт интерфейса конечного пользователя с системой. Стандарт проектирования должен устанавливать: Набор необходимых моделей (диаграмм) на каждой стадии проектирования и степень их детализации. Правила фиксации проектных решений на диаграммах, в том числе правила именования объектов (включая соглашения по терминологии), набор атрибутов для всех объектов и правила их заполнения на каждой стадии, правила оформления диаграмм (включая требования к форме и размерам объектов) и т.д. Требования к конфигурации рабочих мест разработчиков, включая настройки ОС, настройки CASE – средств и т.д. Механизм обеспечения совместной работы над проектом, в том числе правила интеграции подсистем проекта, правила поддержания проекта в одинаковом для всех разработчиков состоянии (регламент обмена проектной информацией, механизм фиксации общих объектов и т.д.), правила анализа проектных решений на непротиворечивость и т.д. Стандарт оформления проектной документации. Он должен устанавливать: комплектность, состав и структуру документации на каждой стадии проектирования (в соответствии со стандартом ГОСТ Р ИСО 9127 – 94 «Системы обработки информации. Документация пользователя и информация на упаковке потребительских программных пакетов»); требования к оформлению документации (включая требования к содержанию разделов, подразделов, пунктов, таблиц и т.д.); правила подготовки, рассмотрения, согласования и утверждения документации с указанием предельных сроков на каждой стадии; требования к настройке издательской системы, используемой в качестве встроенного средства подготовки документации; требования к настройке CASE – средств для обеспечения подготовки документации в соответствии с установленными правилами. Стандарт интерфейса конечного пользователя с системой. Он должен регламентировать: Правила оформления экранов (шрифты и цветовая палитра), состав и расположение окон и элементов управления. Правила использования клавиатуры и мыши. Правила оформления текстов помощи. Перечень стандартных сообщений. Правила обработки реакций пользователя. Стандарт пользовательского интерфейса для диалоговых информационных технологий фирмы IBM с некоторыми пояснениями приведен в приложении 1 данной работы. Детальное конструирование ПО СУЩНОСТЬ СТРУКТУРНОГО ПОДХОДА. МЕТОДЫ ДОКУМЕНТИРОВАНИЯ ПО Сущность структурного подхода. Принципы, на которых базируется структурный подход. Метод SADT. Метод DFD. Проблема сложности является главной проблемой, которую приходится решать при создании больших систем любой природы, в том числе и ЭИС. Ни один разработчик не в состоянии выйти за пределы человеческих возможностей и понять все систему в целом. Единственно эффективный подход к решению этой проблемы заключается в построении сложной системы из небольшого количества крупных частей, каждая из которых, в свою очередь, строится из частей меньшего размера и т.д., до тех пор, пока самые небольшие части можно будет строить из имеющегося материала. Этот подход известен под самыми разными названиями, среди них такие, как «разделяй и властвуй», иерархическая декомпозиция и др. по отношению к проектированию сложной программной системы это означает, что ее необходимо разделять (декомпозировать) на небольшие подсистемы, каждую из которых можно разрабатывать независимо от других. Это позволяет при разработке подсистемы любого уровня держать в уме информацию только о ней, а не обо всех остальных частях системы. Правильная декомпозиция является главным способом преодоления сложности разработки больших систем. Понятие «правильная» по отношению к декомпозиции означает следующее: 1. Количество связей между отдельными подсистемами должно быть минимальным. 2. Связность отдельных частей внутри каждой подсистемы должна быть максимальной. Структура системы должна быть таковой, чтобы все взаимодействия между ее подсистемами укладывались в ограниченные, стандартные рамки: 1. Каждая подсистема должна инкапсулировать свою содержимое (скрывать его от других подсистем). 2. Каждая подсистема должна иметь четко определенный интерфейс с другими подсистемами. На сегодняшний день в программной инженерии существуют два основных подхода к разработке ПО ЭИС, принципиальное различие которых обусловлено разными способами декомпозиции систем. Первый подход называется функционально-модульным или структурным. В его основу положен принцип функциональной декомпозиции, при которой структура системы описывается в терминах иерархии ее функций и передачи информации между отдельными функциональными элементами. Второй, объектно-ориентированный подход использует объектную декомпозицию. При этом структура системы описывается в терминах объектов и связей между ними, а поведение системы описывается в терминах обмена сообщениями между объектами. Итак, сущность структурного подхода к разработке ПО ЭИС заключается в ее декомпозиции (разбиении) на автоматизируемые функции: система разбивается на функциональные подсистемы, которые, в свою очередь, делятся на подфункции, те - на задачи и так далее до конкретных процедур. При этом система сохраняет целостное представление, в котором все составляющие компоненты взаимоувязаны. При разработке системы «снизу-вверх», от отдельных задач ко всей системе, целостность теряется, возникают проблемы при описании информационного взаимодействия отдельных компонентов. Все наиболее распространенные методы структурного подхода базируются на ряде общих принципов: 1. Принцип «разделяй и властвуй»; 2. Принцип иерархического упорядочения- принцип организации составных частей системы в иерархические древовидные структуры с добавлением новых деталей на каждом уровне. Выделение двух базовых принципов не означает, что остальные принципы являются второстепенными, т.к. игнорирование любого из них может привести к непредсказуемым последствиям (в том числе и к провалу всего проекта»). Основными из этих принципов являются: 1. Принцип абстрагирования- выделение существенных аспектов системы и отвлечение от несущественных. 2. Принцип непротиворечивостиобоснованность и согласованность элементов системы. 3. Принцип структурирования данных - данные должны быть структурированы и иерархически организованы. В структурном подходе в основном две группы средств, описывающих функциональную структуру системы и отношения между данными. Каждой группе средств соответствуют определенные виды моделей (диаграмм), наиболее распространенными среди них являются: DFD (Data Flow Diagrams) - диаграммы потоков данных; SADT (Structured Analysis and Design Technique - метод структурного анализа и проектирования) - модели и соответствующие функциональные диаграммы; ERD (Entity - Relationship Diagrams) - диаграммы «сущность-связь». Практически во всех методах структурного подхода (структурного анализа) на стадии формирования требований к ПО используются две группы средств моделирования: 1. Диаграммы, иллюстрирующие функции, которые система должна выполнять, и связи между этими функциями - DFD или SADT (IDEF0). 2. Диаграммы, моделирующие данные и их отношения (ERD). Конкретный вид перечисленных диаграмм и интерпретация их конструкций зависят от стадии ЖЦ ПО. На стадии формирования требований к ПО SADT - модели и DFD используются для построения модели “AS-IS” и модели “TO-BE”, отражая таким образом существующую и предлагаемую структуру бизнес - процессов организации и взаимодействие между ними (использование SADT - моделей , как правило, ограничивается только данной стадией, поскольку они изначально не предназначались для проектирования ПО). С помощью ERD выполняется описание используемых в организации данных на концептуальном уровне, не зависимо от средств реализации базы данных (СУБД). На стадии проектирования DFD используются для описания структуры проектируемой системы. Перечисленные модели в совокупности дают полное описание ПО ЭИС независимо от того, является ли система существующей или вновь разрабатываемой. ТЕМА 7. ТЕСТИРОВАНИЕ ПО ТЕСТИРОВАНИЕ - СПОСОБ ОБЕСПЕЧЕНИЯ КАЧЕСТВА Качество программного продукта характеризуется набором свойств,определяющих, насколько продукт "хорош" с точки зрения заинтересованных сторон, таких как заказчик продукта, спонсор,конечный пользователь, разработчики и тестировщики продукта, инженеры поддержки, сотрудники отделов маркетинга, обучения и продаж. Каждый из участников может иметь различное представление о продукте и о том,насколько он хорош или плох, то есть о том, насколько высоко качество продукта. Таким образом, постановка задачи обеспечения качества продукта выливается в задачу определения заинтересованных лиц, их критериев качества и затем нахождения оптимального решения,удовлетворяющего этим критериям. Тестирование является одним из наиболее устоявшихся способов обеспечения качества разработки программного обеспечения и входит в набор эффективных средств современной системы обеспечения качества программного продукта. Правильное определение тестирования таково: Тестирование — процесс выполнения программы с намерением найти ошибки. Невозможно гарантировать отсутствие ошибок в нетривиальной программе; в лучшем случае можно попытаться показать наличие ошибок. Если программа правильно ведет себя для солидного набора тестов, нет основании утверждать, что в ней нет ошибок; со всей определенностью можно лишь утверждать, что не известно, когда эта программа не работает. Конечно, если есть причины считать данный набор тестов способным с большой вероятностью обнаружить все возможные ошибки, то можно говорить о некотором уровне уверенности в правильности программы, устанавливаемом этими тестами. Психологические эксперименты показывают, что большинство людей, поставив цель (например, показать, что ошибок нет), ориентируется в своей деятельности на достижение этой цели. Тестовик подсознательно не позволит себе действовать против цели, т. е. подготовить тест, который выявил бы одну из оставшихся в программе ошибок. Поскольку мы все признаем, что совершенство в проектировании и кодировании любой программы недостижимо и поэтому каждая программа содержит некоторое количество ошибок, самым плодотворным применением тестирования будет найти некоторые из них. Если мы хотим добиться этого и избежать психологического барьера, мешающего нам действовать против поставленной цели, наша цель должна состоять в том, чтобы найти как можно больше ошибок. Сформулируем основополагающий вывод: Если ваша цель — показать отсутствие ошибок, вы. их найдете не слишком много. Если же ваша цель — показать наличие ошибок, вы найдете значительную их часть. Надежность невозможно внести в программу в результате тестирования, она определяется правильностью этапов проектирования. Наилучшее решение проблемы надежности — с самого начала не допускать ошибок в программе. Однако вероятность того, что удастся безупречно спроектировать большую программу, бесконечно мала. Роль тестирования состоит как раз в том, чтобы определить местонахождение немногочисленных ошибок, оставшихся в хорошо спроектированной программе. Попытки с помощью тестирования достичь надежности плохо спроектированной программы совершенно бесплодны. Тестирование оказывается довольно необычным процессом (вот почему оно и считается трудным), так как этот процесс разрушительный. Ведь цель проверяющего (тестовика) — заставить программу сбиться. Он доволен, если это ему удается; если же программа на его тесте не сбивается, он не удовлетворен. Еще одна причина, по которой трудно говорить о тестирова- нии — это тот факт, что о нем известно очень немногое. ОСНОВНЫЕ ОПРЕДЕЛЕНИЯ Хотя в тестировании можно выделить несколько различных процессов, такие термины, как тестирование, отладка, доказательство, контроль и испытание, часто используются как синонимы и, к сожалению, для разных людей имеют разный смысл. Хотя стандартных, общепринятых определений этих терминов нет, попытка сформулировать их была предпринята на симпозиуме по тестированию программ. Нашу классификацию различных форм тестирования мы начнем с того, что дадим эти определения, слегка их дополнив и расширив их список. Тестирование (testing), как мы уже выяснили,-процесс выполнения программы (или части программы) с намерением (или целью) найти ошибки. Доказательство (proof) — попытка найти ошибки в программе безотносительно к внешней для программы среде. Большинство методов доказательства предполагает формулировку утверждений о поведении программы и затем вывод и доказательство математических теорем о правильности программы. Доказательства могут рассматриваться как форма тестирования, хотя они и не предполагают прямого выполнения программы. Многие исследователи считают доказательство альтернативой тестированию — взгляд во многом ошибочный; более подробно это обсуждается в гл. 17. Контроль (verification) — попытка найти ошибки, выполняя программу в тестовой, или моделируемой, среде. Испытание (validation) — попытка найти ошибки, выполняя программу в заданной реальной среде. Аттестация (certification) — авторитетное подтверждение правильности программы, аналогичное аттестации электротехнического оборудования Underwriters Laboratories. При тестировании с целью аттестации выполняется сравнение с некоторым заранее определенным стандартом. Отладка (debugging) не является разновидностью тестирования. Хотя слова «отладка» и «тестирование» часто используются как синонимы, под ними подразумеваются разные виды деятельности. Тестирование — деятельность, направленная на обнаружение ошибок; отладка направлена на установление точной природы известной ошибки, а затем — на исправление этой ошибки. Эти два вида деятельности связаны — результаты тестирования являются исходными данными для отладки. Тестирование модуля, или автономное тестирование (module testing, unit testing) — контроль отдельного программного модуля, обычно в изолированной среде (т. е. изолированно от всех остальных модулей). Тестирование модуля иногда включает также математическое доказательство. Тестирование сопряжении (integration testing) — контроль сопряжении между частями системы (модулями, компонентами, подсистемами). Тестирование внешних функций (external function testing) — контроль внешнего поведения системы, определенного внешними спецификациями. Комплексное тестирование (system testing) — контроль и/или испытание системы по отношению к исходным целям. Комплексное тестирование является процессом контроля, если оно выполняется в моделируемой среде, и процессом испытания, если выполняется в среде реальной, жизненной. Тестирование приемлемости (acceptance testing) — проверка со- ответствия программы требованиям пользователя. Тестирование настройки (installation testing) — проверка соответствия каждого конкретного варианта установки системы с целью выявить любые ошибки, возникшие в процессе настройки системы. Отношения между этими типами тестов и проектной документацией, на которой основывается тест, показаны на рис.3, Спектр подходов к проектированию тестов Рис. 3. Процессы тестирования и их связь с процессами проектирования. ФИЛОСОФИЯ ТЕСТИРОВАНИЯ Тестирование программного обеспечения охватывает целый ряд видов деятельности, весьма аналогичный последовательности процессов разработки программного обеспечения. Сюда входят постановка задачи для теста, проектирование, написание тестов, тестирование тестов и, наконец, выполнение тестов и изучение результатов тестирования. Решающую роль играет проектирование теста. Возможен целый спектр подходов к выработке философии, или стратегии проектирования тестов, изображенный на рис.2. Чтобы ориентироваться в стратегиях проектирования тестов, стоит рассмотреть два крайних подхода, находящихся на границах спектра. Следует отметить также, что многие из тех, кто работает в этой области, часто бросаются в одну или другую крайность. Сторонник (или сторонница) подхода, соответствующего левой границе спектра, проектирует свои тесты, исследуя внешние спецификации или спецификации сопряжения программы или модуля, которые он тестирует. Программу он рассматривает как черный ящик. Позиция его такова: «Меня не интересует, как выглядит эта программа и выполнил ли я все команды или все пути. Я буду удовлетворен, если программа будет вести себя так, как указано в спецификациях». Его идеал — проверить все возможные комбина- ции и значения на входе. Приверженец подхода, соответствующего другому концу спектра, проектирует свои тесты, изучая логику программы. Он начинает с того, что стремится подготовить достаточное число тестов для того, чтобы каждая команда была выполнена по крайней мере один раз. Если он немного более искушен, то проектирует тесты так, чтобы каждая команда условного перехода выполнялась в каждом направлении хотя бы раз. Его идеал — проверить каждый путь, каждую ветвь алгоритма. При этом его совсем (или почти совсем) не интересуют спецификации. Ни одна из этих крайностей не является хорошей стратегией. Читатель, однако, уже, вероятно, заметил, что первая из них, а именно та, в соответствии с которой программа рассматривается как черный ящик, предпочтительней. К сожалению, она страдает тем недостатком, что совершенно неосуществима. Рассмотрим попытку тестирования тривиальной программы, получающей на входе три числа и вычисляющей их среднее арифметическое. Тестирование этой программы для всех значений входных данных невозмож- но. Даже для машины с относительно низкой точностью вычислений количество тестов исчислялось бы миллиардами. Даже имей мы вычислительную мощность, достаточную для выполнения всех тестов в разумное время, мы потратили бы на несколько порядков больше времени для того, чтобы эти тесты подготовить, а затем проверить. Такие программы, как системы реального времени, операционные системы и программы управления данными, которые сохраняют «память» о предыдущих входных данных, еще хуже. Нам потребовалось бы тестировать программу не только для каждого входного значения, но и для каждой последовательности, каждой комбинации входных данных. Поэтому исчерпывающее тестирование для всех входных данных любой разумной программы неосуществимо. Эти рассуждения приводят ко второму фундаментальному принципу тестирования: тестирование — проблема в значительной сте- пени экономическая . Поскольку исчерпывающее тестирование невозможно, мы должны ограничиться чем-то меньшим. Каждый тест должен давать максимальную отдачу по сравнению с нашими затратами. Эта отдача измеряется вероятностью тою, что тест выявит не обнаруженную прежде ошибку. Затраты измеряются временем и стоимостью подготовки, выполнения и проверки результатов теста. Считая, что затраты ограничены бюджетом и графиком, можно утверждать, что искусство тестирования, по существу, представляет собой искусство отбора тестов с максимальной отдачей. Более того, каждый тест должен быть представителем некоторого класса входных значений, так чтобы его правильное выполнение создавало у нас некоторую убежденность в том, что для определенного класса входных данных программа будет выполняться правильно. Это обычно требует некоторого знания алгоритма и структуры программы, и мы, таким образом, смещаемся к правому концу спектра. ИНТЕГРАЦИЯ МОДУЛЕЙ Вторым по важности аспектом тестирования (после проектирования тестов) является последовательность слияния всех модулей в систему или программу. Эта сторона вопроса обычно не получает достаточного внимания и часто рассматривается слишком поздно. Выбор этой последовательности, однако, является одним из самых жизненно важных решении, принимаемых на этапе тестирования, поскольку он определяет форму, в которой записываются тесты, типы необходимых инструментов тестирования, последовательность программирования модулей, а также тщательность и экономичность всего этапа тестирования. По этой причине такое решение должно приниматься на уровне проекта в целом и на достаточно ранней его стадии. Имеется большой выбор возможных подходов, которые могут быть использованы для слияния модулей в более крупные единицы. В большинстве своем они могут рассматриваться как варианты шести основных подходов, описанных в следующих шести разделах. Сразу же за ними идет раздел, где предложенные подходы сравниваются по их влиянию на надежность программного обеспечения. ВОСХОДЯЩЕЕ ТЕСТИРОВАНИЕ При восходящем подходе программа собирается и тестируется снизу вверх. Только модули самого нижнего уровня («терминальные» модули; модули, не вызывающие других модулей) тестируются изолированно, автономно. После того как тестирование этих модулей завершено, вызов их должен быть так же надежен, как вызов встроенной функции языка или оператор присваивания. Затем тестируются модули, непосредственно вызывающие уже проверенные. Эти модули более высокого уровня тестируются не автономно, а вместе с уже проверенными модулями более низкого уровня. Процесс повторяется до тех пор, пока не будет достигнута вершина. Здесь завершаются и тестирование модулей, и тестирование сопря- жении программы. При восходящем тестировании для каждого модуля необходим драйвер: нужно подавать тесты в соответствии с сопряжением тестируемого модуля. Одно из возможных решении — написать для каждого модуля небольшую ведущую программу. Тестовые данные представляются как «встроенные» непосредственно в эту программу переменные и структуры данных, и она многократно вызывает тестируемый модуль, с каждым вызовом передавая ему новые тестовые данные. Имеется и лучшее решение: воспользоваться программой тестирования модулей — это инструмент тестирования, позволяющий описывать тесты на специальном языке и избавляющий от необходимости писать драйверы. НИСХОДЯЩЕЕ ТЕСТИРОВАНИЕ Нисходящее тестирование (называемое также нисходящей разработкой не является полной противоположностью восходящему, но в первом приближении может рассматриваться как таковое, При нисходящем подходе программа собирается и тестируется сверху вниз. Изолировано тестируется только головной модуль. После того как тестирование этого модуля завершено, с ним соеди- няются (например, редактором связей) один за другим модули, непосредственно вызываемые им, и тестируется полученная комбинация. Процесс повторяется до тех пор, пока не будут собраны и проверены все модули. При этом подходе немедленно возникает два вопроса: что делать, когда тестируемый модуль вызывает модуль более низкого уровня (которого в данный момент еще не существует), и как подаются тестовые данные. Ответ на первый вопрос состоит в том, что для имитации функций недостающих модулей программируются модули-заглушки», которые моделируют функции отсутствующих модулей. Фраза «просто напишите заглушку» часто встречается в описании этого подхода, но она способна ввести в заблуждение, поскольку задача написания заглушки» может оказаться трудной. Ведь заглушка редко сводится просто к оператору RETURN, поскольку вызывающий модуль обычно ожидает от нее выходных параметров. В таких случаях в заглушку встраивают фиксированные выходные данные, которые она всегда и возвращает. Это иногда оказывается неприемлемым, так как вызывающий модуль может рассчитывать, что результат вызова зависит от входных данных. Поэтому в некоторых случаях заглушка должна быть довольно изощренной, приближаясь по сложности к модулю, который она пытается моделировать. Интересен и второй вопрос: в какой форме готовятся тестовые данные и как они передаются программе? Если бы головной модуль содержал все нужные операции ввода и вывода, ответ был бы прост: тесты пишутся в виде обычных для пользователей внешних данных и передаются программе через выделенные ей устройства ввода. Так, однако, случается редко. В хорошо спроектированной программе физические операции ввода-вывода выполняются на нижних уровнях структуры, поскольку физический ввод- вывод — абстракция довольно низкого уровня. Поэтому для того, чтобы решить проблему экономически эффективно, модули добавляются не в стро- го нисходящей последовательности (все модули одного горизонтального уровня, затем модули следующего уровня), а таким образом, чтобы обеспечить функционирование операций физического ввода-вывода как можно быстрее. Когда эта цель достигнута, нисходящее тестирование получает значительное преимущество: все дальнейшие тесты готовятся в той же форме, которая рассчитана на пользователя. Остается еще один вопрос: в какой форме пишутся тесты до тех пор, пока не будет достигнута эта цель? Ответ: они включаются в некоторые из заглушек. Нисходящий метод имеет как достоинства, так и недостатки по сравнению с восходящим. Самое значительное достоинство — в том, что этот метод совмещает тестирование модуля, тестирование сопряжении и частично тестирование внешних функций. С этим же связано другое его достоинство — когда модули ввода-вывода уже подключены, тесты можно готовить в удобном виде. Нисходящий подход выгоден также в том случае, когда есть сомнения относительно осуществимости программы в целом или если в проекте программы могут оказаться серьезные дефекты. Преимуществом нисходящего подхода очень часто считают отсутствие необходимости в драйверах; вместо драйверов вам просто следует написать «заглушки». Как читатель сейчас уже, вероятно, понимает, это преимущество спорно. Нисходящий метод тестирования имеет, к сожалению, некоторые недостатки. Основным из них является тот, что модуль редко тестируется досконально сразу после его подключения. Дело в том, что основательное тестирование некоторых модулей может потребовать крайне изощренных заглушек. Программист часто решает не тратить массу времени на их программирование, а вместо этого пишет простые заглушки и проверяет лишь часть условий в модуле. Он, конечно, собирается вернуться и закончить тестирование рассматриваемого модуля позже, когда уберет заглушки. Такой план тестирования определенно не лучшее решение, поскольку об от- ложенных условиях часто забывают. Второй тонкий недостаток нисходящего подхода состоит в том, что он может породить веру в возможность начать программирование и тестирование верхнего уровня программы до того, как вся программа будет полностью спроектирована. Эта идея на первый взгляд кажется экономичной, но обычно дело обстоит совсем наоборот. Большинство опытных проектировщиков признает, что проектирование программы — процесс итеративный. Редко первый проект оказывается совершенным. Нормальный стиль проектирования структуры программы предполагает по окончании проектирования нижних уровней вернуться назад и подправить верхний уровень, внеся в него некоторые усовершенствования или исправляя ошибки, либо иногда даже выбросить проект и начать все сначала, потому что разработчик внезапно увидел лучший подход. Если же головная часть программы уже запрограммирована и оттестирована, то возникает серьезное сопротивление любым улучшениям ее структуры. В конечном итоге за счет таких улучшений обычно можно сэкономить больше, чем те несколько дней или недель, которые рассчитывает выиграть проектировщик, приступая к программированию слишком рано. МОДИФИЦИРОВАННЫЙ НИСХОДЯЩИЙ МЕТОД Нисходящий подход имеет еще один существенный недостаток, касающийся полноты тестирования. Предположим, что есть большая программа и где-то ближе к нижнему ее уровню находится модуль, предназначенный для вычисления корней квадратного уравнения. Для заданных входных переменных А, В и С он решает уравнение. При проектировании и программировании модуля с такой функцией всегда следует понимать, что квадратное уравнение может иметь как действительные, так и комплексные корни. Для полной реализации этой функции необходимо, чтобы результаты могли быть действительными или комплексными числами (или, если дополнительные затраты на нахождение комплексных корней не оправданы, модуль должен по крайней мере возвращать код ошибки в случае, когда входные коэффициенты задают уравнение с комплексными корнями). Предположим, что конкретный контекст, в котором используется модуль, исключает комплексные корни (т. е. вызывающие модули никогда не задают входных параметров, которые привели бы к комплексным корням). При строго нисходящем методе иногда бывает невозможно тестировать модуль для случая комплексных корней (или тестировать ошибочные условия). Можно попытаться оправдывать это тем, что, поскольку такое уравнение никогда не будет дано модулю, никого не должно заботить, работает ли он и в этих случаях. Да, это безразлично сейчас, но окажется важным в будущем, когда кто-то попытается использовать модуль в новой программе или модифицировать старую программу так, что станут возможными и комплексные корни. Эта проблема проявляется в разнообразных формах. Применяя нисходящее тестирование в точном соответствии с предыдущим разделом, часто невозможно тестировать определенные логические условия, например ошибочные ситуации или защитные проверки. Нисходящий метод, кроме того, делает сложной или вообще невозможной проверку исключительных ситуаций в некотором модуле, если программа работает с ним лишь в ограниченном контексте (это означает, что модуль никогда не получит достаточно полный набор входных значений). Даже если тестирование такой ситуации в принципе осуществимо, часто бывает трудно определить, какие именно нужны тесты, если они вводятся в точке программы, удаленной от места проверки соответствующего условия. Метод, называемый модифицированным нисходящим подходом, решает эти проблемы: требуется, чтобы каждый модуль прошел автономное тестирование перед подключением к программе. Хотя это действительно решает все перечисленные проблемы, здесь требуются и драйверы, и заглушки для каждого модуля. |