67305

Верификация, тестирование и оценивание корректности программных компонентов

Лекция

Информатика, кибернетика и программирование

Принципы верификации и тестирования программ Верификация  это процесс для определения выполняют ли программные средства и их компоненты требования наложенные на них в последовательных этапах ЖЦ ПС. Информация о процессе верификации включает требования к системе требования к ПС и к его архитектуре данные...

Русский

2014-09-07

292.5 KB

14 чел.

PAGE  1

Лекция 13. Верификация, тестирование и оценивание            корректности программных компонентов

13.1. Принципы верификации и тестирования программ

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

Назначение верификации ПС  последовательно проверить, что в реализованном комплексе программ (рис. 13.1):

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

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

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

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

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

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

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

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

При выборе и применении методов тестирования программных компонентов необходимо учитывать общие требования к ним и их особенности:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

13.2. Процессы и средства тестирования программных компонентов

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

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

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

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

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

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

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

         При разработке сложных ПС верификация и тестирование требуют значительных ресурсов в течение всего ЖЦ ПС, и наиболее критичным ресурсом является допустимое время поэтапного выполнения этих процедур. Интенсивность выявления дефектов при тестировании программ практически экспоненциально убывает в зависимости от времени, затрачиваемого на их обнаружение, и соответственно возрастают интервалы между очередными проявлениями дефектов. На основе экспериментальных данных созданы математические модели,   которые позволяют прогнозировать интервалы времени между последовательными обнаружениями дефектов или ошибок в программных компонентах при некотором методе и этапе верификации или тестирования (см. лекцию 10).  Например, если при тестировании определенного модуля или компонента ПС выявлено  определенное число дефектов (например, 5 или 10), то модели позволяют оценить  ресурсы (время), необходимое для обнаружения следующего дефекта и рентабельность продолжения тестирования используемым методом. Рациональное изменение стратегии или метода выявления дефектов может приводить к кратковременному повышению интенсивности их проявления, а затем к постепенному ее снижению.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

 

13.3. Технологические этапы и стратегии систематического             тестирования  программ

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

13.4. Процессы тестирования структуры программных компонентов

    Как отмечалось выше (см. п. 13.1), оценивание корректности программных средств можно представить двумя видами работ:

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

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

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

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

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

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

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

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

         Х2  выделение всех линейно независимых маршрутов, отличающихся  хотя  бы одной дугой в маршруте от остальных;

         Х3  выделение маршрутов при всех возможных комбинациях дуг,
входящих в маршруты.

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

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

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

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

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

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

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

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

       Экспериментально подтверждена адекватность использования структурной сложности программ для оценки трудоемкости тестирования, а также вероятности наличия не выявленных ошибок и затрат на разработку программных модулей в целом. Сложность тестирования ПМ можно оценивать по числу маршрутов M X , необходимых для их проверки, или более полно по суммарному числу условий Е X , которое необходимо задать в тестах для прохождения всех маршрутов  программы, выделенных по Х-му критерию:

      (13.1)

где Е i  число условий-предикатов, определяющих i-й маршрут.

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

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

Маршруты первого вида обычно логически проще и короче, чем второго, и предназначены для преобразования величин, являющихся квантованными результатами измерения некоторых непрерывных физических характеристик (непрерывные переменные). Значения таких переменных связаны условиями гладкости, т.е. условиями малых изменений производных этих переменных по времени или по другим параметрам. При оценке сложности вычислительных маршрутов программ необходим учет числа операндов, участвующих в вычислениях. Кроме того, исходные и результирующие данные при тестировании должны принимать несколько значений. Во всем диапазоне исходных переменных следует выбирать несколько характерных точек (предельные значения и несколько промежуточных), при которых проверяется программа. В особых точках значений и сочетаний переменных и в точках разрыва функции необходимо планировать дополнительные проверки. Таким образом, сложность проверки программного модуля будет определяться числом маршрутов M Х исполнения программы и числом обрабатываемых операндов l i на каждом i-м маршруте, умноженном на число значений s i j для каждой исходной j-й величины на этом маршруте:

      (13.2)

Расчет показателя сложности тестирования программного модуля по такой схеме имеет значительную неопределенность из-за произвола в выборе числа значений s i j  (в основном, особых точек) при варьировании исходных данных в тесте. В то же время доля вычислительной части во многих сложных ПС относительно невелика.

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

Структурная сложность программного модуля может быть рассчитана по числу маршрутов М Х в программе и сложности каждого i-го маршрута Е i . Эти показатели в совокупности определяют минимальную сложность Е Х тестов для проверки программного модуля (13.1), а следовательно, трудоемкость его разработки и тестирования, и вероятность пропуска логической ошибки в программе. Программные модули являются наиболее массовыми компонентами в ПС и требуют для тестирования суммарно наибольших затрат ресурсов. Затраты на тестирование каждого модуля прямо пропорциональны сложности, которая зависит от его структуры и объема вычислений l i . При тестировании  программного модуля необходимо задать и проанализировать число значений параметров:

      (13.3)

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

      (13.4)

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

Сложность тестирования программ, содержащих циклы.  Наличие циклов в программе способно резко увеличивать сложность их тестирования. Полное, исчерпывающее тестирование должно охватывать проверку каждого маршрута в цикле при всех возможных итерациях цикла и при всех сочетаниях циклов с маршрутами ациклической части программы. Предположим для простоты, что число маршрутов в нижней ациклической части программы равно М 3 =1. Тогда полное множество маршрутов M состоит из полной совокупности всех маршрутов M1  в верхней ациклической части программы и группы маршрутов M 2,  в которой к каждому маршруту из M 1 присоединено 1..2..3... итерации (витка) цикла. При этом на каждой итерации выполняется, по крайней мере, один из внутренних маршрутов тела цикла.        

Например, для графа, имеющего один цикл, требующего исполнения пяти итераций (витков) с тремя внутренними маршрутами, а также содержащего M 1 = 10 ациклических маршрутов, проходящих через цикл, суммарное число маршрутов для исчерпывающего тестирования равно M = (3 x 5) x 10 = 150. При возрастании любого из сомножителей (числа независимых ациклических маршрутов, проходящих через цикл, числа внутренних маршрутов тела цикла или числа его итераций) пропорционально растет их произведение,  а, следовательно, и сложность тестирования. Поэтому исчерпывающее тестирование реальных сложных программ с циклами может быть практически невозможно.

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

-  на разных итерациях цикла исполняются независимо  все  возможные   маршруты тела цикла; 

-  на всех итерациях цикла исполняется один и тот же маршрут тела цикла или некоторая определенная их последовательность;

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

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

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

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

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

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

         Сложность тестирования программных компонентов (функциональных групп программ) определяется суммарной сложностью модулей и межмодульных связей по управлению и по информации. Каждый модуль должен тестироваться автономно до включения в группу программ и частично в составе группы. Затраты на тестирование модулей в составе группы программ должны учитывать относительные суммарные затраты на тестирование всех входящих модулей с коэффициентом d k < 1, зависящим от степени предшествующей проверки модуля. Если модули автономно не тестировались (например, при нисходящем тестировании), то d k = 1 и затраты на тестирование каждого модуля войдут в затраты при тестировании группы программ в полном объеме. При тщательном автономном тестировании модулей можно полагать d k = 0,1-0,01, т.е. в составе ПС затраты на тестирование каждого из модулей составляют несколько процентов.

13.5. Примеры оценок сложности тестирования программ 

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

На рис. 13.7 представлен пример исходного графа модуля программы, содержащего 14 вершин, 20 дуг и 3 цикла. Такая программа сравнительно невысокой сложности содержит около 30-50 операторов на языке высокого уровня и может рассматриваться как достаточно типичная. Для полной проверки модуля по первому критерию достаточно четырех маршрутов. По этому критерию гарантируется проверка всех передач управления между операторами программы и каждого оператора не менее одного раза. Самый длинный по числу вершин маршрут не охватывает только 3 вершины из 14 и только 6 дуг из 20.

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

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

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

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

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

Анализ проведен для двух типов  ациклических графов при выделении маршрутов по критерию охвата каждой дуги графа программы хотя бы один раз X1 и по критерию выделения всех маршрутов, различающихся хотя бы одной дугой  Х2 . В числе выбранных содержатся структуры, охватывающие наиболее типовые варианты компонентов графов программ. Структуры различались шириной графов, вследствие чего отличались число маршрутов и сложность полного тестирования таких структур. Сложность тестирования ПМ оценивалась по числу маршрутов исполнения программы, отражающих число тестов, необходимых для полной проверки корректности структуры модуля. Кроме того, в качестве показателя структурной сложности тестирования анализировалось суммарное число условий, которое необходимо задать в тестах (сложность тестирования) для проверки модуля.

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

          Структурная сложность тестирования графов ПМ изменяется в более широком диапазоне, чем число маршрутов, что определило выбор логарифмического масштаба по оси ординат на рис. 13.8.  Наименьшей структурной сложностью характеризуется граф  Г2 при выделении маршрутов по первому критерию. Для таких графов структурная сложность возрастает практически линейно в зависимости от числа вершин. При выделении маршрутов по второму критерию тот же граф характеризуется наибольшей структурной сложностью. При 30 и более вершинах структурная сложность этого графа почти на порядок выше, чем графа Г1  при том же числе вершин. Относительная разница сложности тестирования этих графов при критерии Х2 приблизительно сохраняется при изменении числа вершин от 16 до 100.  Такое распределение значений структурной сложности от типов графов обусловлено различием их ширины. Так как число маршрутов при критерии Х2 в зависимости от числа вершин во всех       графах изменяется практически одинаково, то определяющим различия структурной сложности является число условий анализируемых в каждом маршруте. Во всех маршрутах графа Г2 участвуют все его вершины, что определило его наибольшую структурную сложность.

          На рис 13.8 точками (с указанием числа совпадающих значений) отмечены значения структурной сложности тестирования около 70 реальных ациклических ПМ в двух системах. Характеристики абстрактных графов Г1 и Г2  действительно охватывают диапазон изменения показателей сложности тестов для реальных программ, которые по каждому критерию группируются приблизительно посередине. Максимальная сложность тестов по второму критерию для произвольных ациклических программ близка к числу вершин в квадрате. По тому же критерию минимальная сложность тестов для широких структурированных графов типа дерево на порядок меньше максимальной сложности. Для усредненных оценок сложности полных тестов произвольных ациклических программ хорошее приближение для инженерных оценок при n в  > 10 дает выражение n  в 2 /3  (штриховая линия на рис. 13.8). Характерно, что увеличение числа вершин в 4 раза (от 32 до 128) для рассмотренных графов приводит к возрастанию структурной сложности более чем в 10 раз. Если же программу, имеющую 128 вершин, разделить на 4 модуля, то их суммарная сложность практически равна только учетверенной сложности модулей, содержащих по 32 вершины. Исследованные реальные ПМ 80% случаев содержат не более 10 вершин и имеют  структурную сложность тестирования < 50.

Показано,  что при разработке ПМ целесообразно учитывать рациональное ограничение размеров модулей на уровне трехсот строк текста, что соответствует приблизительно тридцати альтернативам в ациклических программах. При этом для полного покрытия таких ПМ тестами необходимо задавать до 1000 условий, что обычно достаточно  трудно или невозможно реализовать практически. В среднем полное тестирование программ с 30-ю вершинами ветвления производится тестами с суммарной сложностью около 300 – 500. Суммарная сложность тестов, необходимых для полного тестирования программ, имеющих различные структуры, может отличаться в несколько раз.

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

      Для получения практических оценок достигаемой корректности программы при покрытии тестами ее структуры, необходимо оценить диапазон реальной вероятности ошибки допускаемой квалифицированным программистом первично в каждой дуге графа программы. Экспериментально установлено, что для слабо структурированных программ число ошибок, выявляемых в процессе тестирования программных модулей, составляет около одного процента числа строк текста этих модулей. Для программ обработки информации и управления число условных переходов составляет около 10% числа строк в программе, т.е. ветвление в программе происходит в среднем после исполнения 10 строк текста линейных участков. Следовательно, порядка 10% линейных участков (или дуг в графе) программных модулей могут содержать первоначально ошибки перед тестированием, что соответствует вероятности q i j    0,l .

        Использование правил структурного программирования, спецификаций требований на модули и группы программ, а также современной технологии программирования позволяет снизить первичную вероятность ошибок приблизительно на порядок, т.е. до уровня q i j  0,01.  Поэтому оценивание стратегий тестирования и достигаемой при этом корректности целесообразно проводить в диапазоне q i j = 0,10,01, соответствующем практически наихудшим и наилучшим значениям вероятностей ошибок в дуге до тестирования.

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

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

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

13.6. Тестирование обработки потоков данных                                                       программными компонентами

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

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

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

Для построения DFD-диаграмм, формализованы синтаксис и семантика графических элементов: отражающих движение объектов – процедуры программ; описаний внешних сущностей – источников и потребителей данных;  их хранения.  Рекомендуется вначале определять набор действий, описывающих, что должны выполнять процедуры программы. Затем  строить модель окружения – внешние сущности, порождающие процессы и специфическое поведение при обработке данных. Наборы простейших DFD-диаграмм – операторов программы, объединяются в иерархические структуры, отражающие потоки данных в программных модулях или функциональных компонентах из ряда модулей.

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

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

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

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

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

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

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

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

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

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

Предикаты, определяющие выбор маршрутов исполнения программы, могут формироваться в результате вычислений на линейных участках программы. Эти участки в среднем невелики и содержат около 5 10 строк текста программы. Каждая ограниченная область исходных данных соответствует определенному маршруту в программе. Граница области определяется интерпретациями предикатов по маршруту и состоит из набора участков границы, каждый из которых определяется единственным, простым предикатом, выбирающим дугу маршрута в графе программы. Каждый участок границы области может быть открытым или закрытым в зависимости от оператора условий в предикате. Закрытый участок границы принадлежит ограничиваемой области и формируется предикатами с операторами ,    или  = . Открытый участок границы не входит в состав области и формируется операторами  < ,  >  и  . Общее число предикатов в маршруте это верхний предел числа граничных участков области входных переменных данного маршрута, так как некоторые предикаты маршрута могут в действительности не создавать граничных участков. Такие случаи возникают, когда предикат требуется для нескольких путей, и в некоторых из них повторно анализируется на маршруте.

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

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

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

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

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

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

Таким образом, для каждой простой числовой переменной, кроме трех точек вблизи и на границе области определения, обычно необходимо тестирование программы в 3 4 промежуточных и в 2 5 особых точках значений входных данных. При 10 входных переменных и сложных вычислениях в программном модуле для тестирования вычислений может потребоваться до 50 тестовых значений. Группируя и упорядочивая тестовые значения разных переменных, их общее количество можно сократить до 5 10 тестовых наборов.


 

А также другие работы, которые могут Вас заинтересовать

67744. Блок-секция поворотная 9-ти этажная на 36 квартир в п. Октябрьский 435.8 KB
  Состав комплекса работ этапа подземная часть: разработка котлована; возведение конструкций подземной части здания; устройство гидроизоляции; устройство вводов подземных коммуникаций; обратная засыпка котлована и траншей. Забивка свай: Устройство фундаментов производить...
67746. Разработка малярного отделения АТП на 411 автомобилей МАЗ-53371 3.09 MB
  Малярные работы являются завершающими при ремонте кузова автомобиля, потому в малярный участок автомобили поступают после выполнения всех видов работ. При организации работы в малярном участке наибольшее число рабочих мест создается для подготовки автомобиля к окраске.
67748. Проектирование систем отопления и вентиляции жилого дома в г.Троицкое 2.45 MB
  Цель: рассчитать толщину утепляющего слоя, термическое сопротивление ограждения и коэффициент теплопередачи. Теплотехнический расчет выполняется для наружной стены, подвального, чердачного перекрытий, наружной входной двери. Теплотехнический расчет наружной стены Определяем градусо-сутки отопительного...
67749. АРИФМЕТИКА МНОГОЧЛЕНОВ 461 KB
  Множество всех многочленов от одной переменной над полем образует коммутативное кольцо с единицей. В кольце многочленов имеет место алгоритм деления с остатком аналогичный тому который имеет место для целых чисел. Если для многочленов и в кольце существуют такие многочлены и что многочлен можно представить...
67750. Програмування в Mathcad. Освоєння основ програмування в Mathcad 59.5 KB
  Привести тестові приклади для розроблених програм Елементи вектору можуть бути дійсними або комплексними Знайти елемент вектору максимальний мінімальнний з максимальним значенням дійсної частини з мінімальним значення уявної частини максимальний по модулю...
67751. АРИФМЕТИКА ОСТАТКОВ 524 KB
  Для произвольного приведённого многочлена ненулевой степени над полем кольцом многочленов по модулю называется множество всех многочленов над этим полем, степени которых не превышают степень самого многочлена, с операциями сложения и умножения многочленов по модулю.