Раздел 2. Обеспечение качества программных компонент


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

2.1.1. Принципы построения компонент для обеспечения надежности функционирования программных средств

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

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

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

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

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

надежность функционирования и безопасность применения;

эффективное использование памяти и производительности компьютера;

трудоемкость или длительность разработки;

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

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

 

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

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

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

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

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

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

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

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

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

 

2.1.3. Методы и стратегии тестирования программных компонент

Существуют две основные стратегии тестирования программных модулей (компонент):

структурное тестирование (тестирование «белого ящика», тестирование, управляемое логикой программы, тестирование потоков управления.),

функциональное тестирование (тестирование «черного ящика», тестирования потоков данных).

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

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

 

Not Supported

 

а б

 

Рисунок 2.1. – а) схема структурного тестирования,

б) схема функционального тестирования

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

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

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

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

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

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

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

 

2.1.4. Этапы и задачи тестирования программных компонент

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

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

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

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

Рассмотрим подробнее эти этапы и решаемые на них задачи.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

 

2.2. Тестирование структуры программных компонент

 

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

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

При планировании тестирования структуры программ возникают, прежде всего, две задачи:

— формирование критериев выделения маршрутов для тестирования;

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

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

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

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

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

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

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

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

числа строк текста в выделенном маршруте (1 стратегия),

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

вероятности исполнения маршрутов при реальном функционировании программы (3 стратегия).

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

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

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

 

2.2.2. Сложность тестирования структуры программных модулей

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

,

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

Рассмотрим пример оценки сложности тестирования программ при различных критериях выделения маршрутов. На рис. 2.2 представлен пример исходного графа модуля программы, содержащего 14 вершин, 20 дуг и 3 цикла. Такая программа содержит около 30-50 операторов на языке высокого уровня и может рассматриваться как достаточно типичная.

 

Not Supported

 

Рисунок 2.2 – Пример графа программного модуля

Для полной проверки модуля по первому критерию достаточно четырех маршрутов (Е — количество предикатных вершин на маршруте):

1-2-14 (Е1= 1),

1-3-4-6-8-6-8-14 (Е2= 5),

1-3-5-7-9-10-11-12-14 (Е3= 5),

1-3-4-5-7-9-10-9-10-11-7-9-10-11-12-13-14 (Е4= 9).

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

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

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

Цикломатическое число вычисляется одним из трех способов:

Цикломатическое число равно количеству регионов потокового графа;

По формуле V = E – N + 2,

где V – цикломатическая сложность,

Е – количество дуг графа,

N – количество узлов графа.

3. По формуле V = p + 1,

где р – количество предикатных узлов графа.

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

Для нашего примера V = 8.

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

6-8-6;

9-10-9;

7-9-10-11-7

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

1-2-14;

1-3-4-6-8-14;

1-3-5-7-9-10-11-12-14;

1-3-4-5-7-9-10-11-12-13-14;

1-3-4-5-7-9-10-11-12-14.

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

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

 

2.2.3. Сложность тестирования ациклических программных модулей

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

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

 

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

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

Рассмотрим пример графа программы с циклом (рис.2.3).

Предположим для простоты, что число маршрутов в нижней ациклической части программы М3 =1. Тогда полное множество маршрутов М состоит из полной совокупности всех маршрутов М1 в верхней ациклической части программы и группы маршрутов М2, в которой к каждому маршруту из М1 присоединено 1, 2… итерации (витка) цикла, причем на каждой итерации выполняется по крайней мере один из внутренних маршрутов тела цикла.

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

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

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

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

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

Not Supported

Рисунок 2.3 – Пример графа программы с циклом

 

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

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

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

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

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

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

 

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

 

2.3.1. Методы и виды тестирования обработки данных

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

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

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

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

— полностью изменяющий область определения и значения результатов;

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

Not Supported

 

Рисунок 2.4 – Пример графа программы с потоком управления

и потоком данных

 

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

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

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

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

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

Тестирование на полное соответствие состава, значений и точности выходных данных спецификации требований.

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

 

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

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

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

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

 

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

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

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

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

операция записи существует, но запись выполняется не в тот регистр;

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

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

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

 

2.3.4. Тестирование корректности обработки каждой переменной и точности результатов вычислений

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

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

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

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

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

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

Таким образом, для каждой простой числовой переменной, кроме трех точек вблизи и на границах области определения, обычно необходимо тестирование программы в 3-4 промежуточных и в 2-5 особых точках значений входных данных. Если переменные представлены в виде массивов, то объем тестирования значительно увеличивается. В этом случае необходимо учитывать структуру и размер массива, наличие в структуре особых точек или подструктур.

 

2.4. Средства автоматизации тестирования программных компонент

 

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

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

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

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

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

автоматизированное планирование тестирования;

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

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

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

Средства автоматизации тестирования делятся на статистические и динамические.

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

средства контроля структурной корректности программ,

средства контроля записи и чтения переменных,

средства поиска устойчивых семантических ошибок,

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

средства расчета продолжительности использования модулей.

При использовании динамических средств программы исполняются в объектном коде. Средства динамического тестирования делятся на:

— основные средства, которые обеспечивают исполнение программ в соответствии с тестовыми заданиями и

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

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

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

 

2.5. Методика тестирования программных компонент

 

2.5.1. Цель методики и исходные данные для тестирования

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

Исходными данными для тестирования, которые нужно фиксировать и документировать до начала работ являются:

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

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

описание программы в виде печатного документа,

руководство пользователя,

исходный текст программы.

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

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

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

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

Допуски на отклонение результатов функционирования и показателей качества от эталонных значений.

Реальные ресурсы тестирования и отладки.

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

Выбор метода тестирования соответствующего основной цели.

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

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

Реализация процесса тестирования и получение результатов.

Сравнение результатов с эталонами.

Диагностика, локализация и исправление ошибок и дефектов.

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

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

 

2.5.2. Реализация процесса тестирования программных компонент

Процесс тестирования выполняется в несколько этапов.

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

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

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

На 4 этапе выполняется анализ потоков данных. Производится тестирование корректности обработки данных без исполнения программы. Цель этого этапа — установление соответствия между областями определения наборов данных и маршрутами их обработки в программе.

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

На 6 этапе производится обработка результатов тестирования и оценка качества и корректности компоненты.

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

программа имеет корректную структуру,

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

каждый из маршрутов завершается за конечное число шагов,

нет несоответствия маршрутов и данных,

нет нереализованных и тупиковых маршрутов,

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

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

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

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

 

2.5.3. Документирование результатов тестирования программных компонент

При тестировании программ создается и используется документация 2-х видов:

документация, отражающая состояние объектов тестирования,

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

Каждый документ должен иметь:

сформулированные назначение и область его действия,

категории специалистов, для которых он предназначен и которыми он разрабатывается,

этапы работ, на которых его нужно применить,

функционирующую, содержательную часть в соответствии с его назначением.

Система документирования процессов и результатов тестирования представлена в стандарте ANSI/IEEE 829, которую нужно использовать как основу при реальных разработках. Система документирования охватывает:

— планирование тестирования,

— спецификацию тестов,

— отчеты о результатах тестирования.

В плане тестирования рекомендуется формализовать:

— назначение плана и цели тестирования,

— объекты, подлежащие тестированию,

— состав справочных материалов и определения основных терминов,

— организацию работ, основной график их выполнения,

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

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

— номенклатуру оформляемых отчетных документов.

В спецификации тестов должны быть отражены:

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

— описания тестов и контрольных примеров,

— спецификация процедур и сценариев тестирования.

Отчеты о результатах тестирования должны включать документы:

— журнал тестирования, в котором регистрируются операции, выполненные во время тестирования, и изменения, которые произведены в программах,

— отчет о дефектах, которые требуют дальнейшего изучения,

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