Загрузка...

Методы обеспечения высокого качества разрабатываемого программного обеспечения


Понятие тестирования. Основные принципы тестирования.

 

Тестирование — это процесс выполнения программы с целью обнаружения ошибок.

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

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

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

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

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

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

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

2. Хорошим считается тест, который имеет высокую веро­ятность обнаружения еще не выявленной ошибки. Удачным считается тест, который обнаруживает еще не выявленную ошибку.

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

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

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

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

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

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

5. Необходимо досконально изучать результаты примене­ния каждого теста.

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

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

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

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

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

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

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

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

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

 

Структурное тестирование программного обес­печения

Существует 2 основных стратегии тестирования структурных программ:

структурное тестирование или тестирование «белого ящика»;

функциональное тестирование или тестирование «черного ящика»

 

3.2.1. Тестирование «белого ящика»

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

Not Supported

Рисунок 3.2.Тестирование «белого ящика»

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

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

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

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

гарантируется проверка всех независимых маршрутов программы;

проходятся ветви «истина» и «ложь» для всех логических решений;

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

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

Недостатки тестирования «белого ящика»:

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

При п = 5 и k = 20 количество маршрутов т = 1014. Примем, что на разработку, выполнение и оценку теста по одному маршруту расходуется 1 мс. Тогда при работе 24 часа в сутки 365 дней в году на тестирование уйдет 3170 лет.

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

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

В программе могут быть пропущены некоторые маршруты.

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

Достоинства тестирования «белого ящика» в том, что эта стратегия позволяет учесть особенности программных ошибок:

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

Количество ошибок минимально в «центре» и максимально на «периферии» программы;

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

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

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

 

3.2.2. Тестирование «черного ящика»

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

Not Supported

Рисунок 3.3. Тестирование «черного ящика»

 

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

Принцип «черного ящика» не альтернативен принципу «белого ящика», он обнаруживает другие классы ошибок. Функциональное тестирование не реагирует на многие программные ошибки.

Тестирование «черного ящика» позволяет находить следующие категории ошибок:

Отсутствие функций или некорректность их выполнения;

Ошибки интерфейса;

Ошибки во внешних структурах данных или в доступе к внешней базе данных;

Ошибки инициализации и завершения;

Ошибки характеристик (необходимая емкость памяти т.п.).

Такие категории ошибок методами «белого ящика» выявить невозможно.

 

Методы структурного тестирования

 

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

метод покрытия операторов;

метод покрытия решений;

метод покрытия условий;

метод покрытия решений/условий;

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

метод тестирования базового пути.

 

3.3.1. Метод покрытия операторов

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

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

Not Supported

Рисунок 3.4 – Блок-схема небольшой программы, которая должна быть протестирована

Рассмотри пример. На рис. 3.4 представлена блок-схема небольшой программы, которая должна быть протестирована.

Эквивалентная программа, написанная на языке С++, имеет вид:

 

Void m (const float A, const float B, float X)

{ if (A>1) && Bb == 0)

X=X/A;

If (A==2)ïï(X>1)

X=X+1}

 

Можно выполнить каждый оператор, записав один-единственный тест, который реализовал бы путь асе. То есть, если бы в точке а были установлены значения A = 2, B = 0 и X = 3, каждый оператор выполнялся бы один раз (в действительности X может принимать любое значение).

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

Если при написании программы в первом условии написать A>1 || B=0, то ошибка обнаружена не будет.

Если во втором условии вместо X>1 записано X>0, то ошибка не будет обнаружена.

Существует путь abd, в котором X вообще не меняется. Если здесь ошибка, то и она не будет обнаружена.

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

 

3.3.2. Метод покрытия решений

Более сильный критерий покрытия логики программы – крите­рий покрытия решений. Решение – это логическая функция, предшествующая оператору (A>1 && B=0 – решение). Для реали­зации этого критерия необходимо такое количество тестов, чтобы каждое решение на этих тестах принимало значение «истина» или «ложь», по крайней мере, один раз. Иными словами, каждое на­правление перехода должно быть реализовано хотя бы один раз.

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

В программе, представленной на рис. 3.4, покрытие решений может быть выполнено двумя тестами, покрывающими либо пути асе и abd, либо пути acd и аbе.

Если мы выбираем второе покрытие, то входами двух тестов являются:

A=3, B=0, X=3

A=2, B=1, X=1

Покрытие решений — более сильный критерий, чем по­крытие операторов, но и он имеет свои недостатки. Например, путь, где X не изменяется (если выбрано покрытие асе и abd), будет проверен с вероятностью 50%. Если во втором решении существует ошибка (например, X < 1 вместо X > 1), то ошибка не будет обнаружена двумя тестами предыдущего примера.

 

Метод покрытия условий

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

Приведенная программа имеет 4-е условия:

A>1, B = 0, A = 2, X>1

Необходимо такое количество тестов, чтобы реализовать ситуации:

A>1, A<=1; B= 0, B!=0 в точке а;

A==2, A!=2; X>1, X<=1 в точке b.

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

A=2, B=0, X=4 (ace)

A=1, B=1, X=1 (abd)

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

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

A = 1, B=0, X=3

A=2, B=1, X=1

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

 

Метод покрытия решений/условий

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

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

 

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

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

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

 

1. A>1, B=0;

2. A>1, B!=0;

3. A<=1, B=0;

4. A<=1, B!=0;

5. A=2, X>1;

6. A=2, X<=1;

7. A!=2, X>1;

8. A!=2, X<=1.

 

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

1. A=2, B=0, X=4 K: 1, 5 2. A=2, B=1, X=1 K: 2, 6

3. A=1, B=0, X=2 K: 3, 7 4. A=1, B=1, X=1 K: 4, 8

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

 

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

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

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

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

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

передающих управление каждой точке входа программы, по крайней мере, один раз. (Слово «возможных» употреблено потому, что некоторые комбинации условий могут быть нереализуемыми; например, для комбинаций K<0, K>40 задать К невозможно.)

 

3.3.6. Метод тестирования базового пути

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

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

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

Свойства потокового графа.

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

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

Дуги отображают поток управления в программе (передачи управления между операторами).

Различают операторные и предикатные узлы. Их операторного узла выходит 1 дуга, из предикатного — 2.

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

 

if a or b

then X

else Y

end if

 

вместо прямого отображения в потоковый граф вида, показанного на рис. 3.5, отображается в преобразованный потоковый граф (рис. 3.6).

Not Supported Not Supported

Рисунок 3.5.Прямое ото- Рисунок 3.6. — Преобразованный

бражение в потоковый граф потоковый граф

 

6. Замкнутые области, образуемые дугами и узлами, называ­ются регионами.

7. Окружающая граф среда рассматривается как дополнитель­ный регион (рис. 3.6).

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

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

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

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

По формуле V = EN + 2,

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

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

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

3. По формуле V = p + 1, где р – количество предикатных узлов графа.

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

 

Пример.

Рассмотрим процедуру сжатия:

процедура сжатие

1       выполнять пока нет EOF

1           читать запись;

2          если запись пуста

3          то удалить запись:

4          иначе если поле а >= поля b

5             то удалить b;

6             иначе удалить а;

         конец если;

      конец если;

7b       конец выполнять;

8    конец сжатие;

 

Она отображается в потоковый граф, представленный на рис. 3.7.

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

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

Путь 1: 1 — 8.

Путь 2: 1 – 2 – 3 — 7а — 7b – 1 — 8.

Путь 3: 1 – 2 – 4 – 5 — 7а — 7b – 1 — 8.

Путь 4: 1 – 2 – 4 – 6 — 7а — 7b – 1 — 8.

 

Not Supported

Рисунок 3.7. — Пример потокового графа

 

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

На основе текста программы формируется потоковый граф.

Определяется цикломатическая сложность (по каждой из трех формул).

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

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

Реальные результаты каждого теста сравниваются с ожидаемыми.

 

3.4. Методы функционального тестирования

 

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

Метод эквивалентных разбиений;

Метод анализа граничных значений;

Метод анализа причинно-следственных связей;

Метод предположения об ошибке.

 

3.4.1. Метод эквивалентных разбиений

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

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

Классы эквивалентности могут быть определены по специфи­кации на программу. Например, если спецификация задает в каче­стве допустимых входных величин 5-разрядные целые числа в диа­пазоне 15 000…70 000, то класс эквивалентности допустимых ис­ходных данных (правильный класс эквивалентности) включает ве­личины от 15 000 до 70 000, а два класса эквивалентности недопус­тимых исходных данных (неправильные классы эквивалентности) составляют:

числа меньшие, чем 15 000;

числа большие, чем 70 000.

 

Правила формирования классов эквивалентности.

Если условие ввода задает диапазон п…т, то определяются:

один правильный класс эквивалентности: n х ≤ т

и два неправильных класса эквивалентности: х < п;

х > т.

2.   Если условие ввода задает конкретное значение а, то определяется

один правильный класс эквивалентности: х = а;

и два неправильных класса эквивалентности: х < а;

х >а.

3.   Если условие ввода задает множество значений {а, b, с}, то определяются

один правильный класс эквивалентности: х =а, х = b, х = с;

и один недопустимый класс эквивалентности:

а)&(х b)&(х с).

4.   Если условие ввода задает булево значение, например true, то определяются

один правильный класс эквивалентности {true}

и один неправильный класс эквивалентности {f alse}.

После построения классов эквивалентности разрабатываются тестовые варианты. Этот процесс включает следующие шаги:

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

 

 

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

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

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

Недостаток метода эквивалентных разбиений в том, что он не исследует комбинации входных условий.

 

3.4.2. Метод анализа граничных значений

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

Сформулируем правила анализа граничных значений.

1. Если условие ввода задает диапазон п…т, то тестовые варианты должны быть построены:

для значений п и т;

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

Например, если задан входной диапазон -1,0…+1,0, то создаются тесты для значений — 1,0, +1,0, — 1,001, +1,001.

2. Если условие ввода задает дискретное множество значений, то создаются тестовые варианты:

для проверки минимального и максимального из значений;

для значений чуть меньше минимума и чуть больше максимума.

Так, если входной файл может содержать от 1 до 255 записей, то создаются тесты для 0, 1, 255, 256 записей.

3. Правила 1 и 2 применяются к условиям области вывода.

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

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

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

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

 

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

Предусловия:

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

2) массив должен иметь не менее одного элемента;

3) нижняя граница массива (индекс) должна быть меньше или равна его верхней границе.

Постусловия:

1) если элемент найден, то флаг Result=True, значение Iномер элемента;

2) если элемент не найден, то флаг Result=False, значение I не определено.

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

1) массив из одного элемента;

2) массив из четного количества элементов;

3) массив из нечетного количества элементов, большего 1.

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

1) работа с первым элементом массива;

2) работа с последним элементом массива;

3) работа с промежуточным (ни с первым, ни с последним) элементом массива.

Структура дерева разбиений приведена на рис.3.8.

Not Supported

 

Рисунок 3.8. Дерево разбиений области исходных данных бинарного поиска

 

Это дерево имеет 11 листьев. Каждый лист задает отдельный тестовый вариант. Покажем тестовые варианты, основанные на проведенных разбиениях (ИД — исходные данные, ОЖ.РЕЗ. — ожидаемый результат).

Тестовый вариант 1 (единичный массив, элемент найден) ТВ1:

ИД: М=15; Кеу=15.

ОЖ.РЕЗ.: Resutt=True; I=1.

Тестовый вариант 2 (четный массив, найден 1-й элемент) ТВ2:

ИД: М=15, 20, 25,30,35,40; Кеу=15.

ОЖ.РЕЗ.: Result=True; I=1.

Тестовый вариант 3 (четный массив, найден последний элемент) ТВЗ:

ИД: М=15, 20, 25, 30, 35, 40; Кеу=40.

ОЖ.РЕЗ:. Result=True; I=6.

Тестовый вариант 4 (четный массив, найден промежуточный элемент) ТВ4:

ИД: М=15,20,25,30,35,40; Кеу=25.

ОЖ.РЕЗ.: Result-True; I=3.

Тестовый вариант 5 (нечетный массив, найден 1-й элемент) ТВ5:

ИД: М=15, 20, 25, 30, 35,40, 45; Кеу=15.

ОЖ.РЕЗ.: Result=True; I=1.

Тестовый вариант 6 (нечетный массив, найден последний элемент) ТВ6:

ИД: М=15, 20, 25, 30,35, 40,45; Кеу=45.

ОЖ.РЕЗ.: Result=True; I=7.

Тестовый вариант 7 (нечетный массив, найден промежуточный элемент) ТВ7:

ИД: М=15, 20, 25, 30,35, 40, 45; Кеу=30.

ОЖ.РЕЗ.: Result=True; I=4.

Тестовый вариант 8 (четный массив, не найден элемент) ТВ8:

ИД: М=15, 20, 25, 30, 35,40; Кеу=23.

ОЖ.РЕЗ.: Result=False; I=?

Тестовый вариант 9 (нечетный массив, не найден элемент) ТВ9;

ИД: М=15, 20, 25, 30, 35, 40, 45; Кеу=24.

ОЖ.РЕЗ:. Result=False; I=?

Тестовый вариант 10 (единичный массив, не найден элемент) ТВ10:

ИД: М=15; Кеу=0.

ОЖ.РЕЗ.: Result=False; I=?

Тестовый вариант 11 (нарушены предусловия) ТВ11:

ИД: М=15, 10, 5, 25, 20, 40, 35; Кеу=35.

ОЖ.РЕЗ.: Аварийное донесение: Массив не упорядочен.

 

3.4.3. Метод анализа причинно-следственных связей

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

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

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

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

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

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

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

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

 

3.4.4. Метод предположения об ошибке

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

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

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

Сортируемый список пуст.

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

Все записи в сортируемом списке имеют одно и тоже значение.

Список уже отсортирован.

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

 

3.5. Организация процесса тестирования программ­ ного обеспечения

 

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

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

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

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

1.   Тестирование элементов. Цельиндивидуальная проверка каждого модуля. Используются способы тестирования «белого ящика».

Not Supported

Рисунок 3.9. — Спираль процесса тестирования ПС

 

2.   Тестирование интеграции. Цель — тестирование сборки модулей в программную систему. В основном применяют способы тестирования «черного ящика».

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

4.   Системное тестирование. Цель — проверка правильности объединения и взаимодействия всех элементов компьютерной системы, реализации всех системных функций.

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

3.5.2. Виды тестов по RUP

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

Рассмотрим основные виды тестов по RUP:

функциональное тестирование;

тестирование целостности баз данных;

тестирование бизнесциклов;

тестирование пользовательского интерфейса;

профилирование производительности;

нагрузочное тестирование;

стрессовое тестирование;

объемное тестирование;

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

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

конфигурационное тестирование;

инсталляционное тестирование.

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

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

 

3.5.2.1. Функциональное тестирование

Цель тестирования: убедиться в правильном функционирова­нии объекта тестирования. Тестируется правильность навигации по объекту, а также ввод, обработка и вывод данных.

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

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

 

3.5.2.2. Тестирование целостности данных и баз данных

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

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

 

3.5.2.3. Тестирование бизнесциклов

Цель тестирования: проверить правильность функционирова­ния объекта тестирования и связанных с ним процессов на соответ­ствие требованиям бизнесмоделей и расписаний.

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

 

3.5.2.4. Тестирование пользовательского интерфейса

Цель тестирования: проверить правильность навигации по объекту тестирования (в том числе межоконные переходы, переходы между полями, правильность обработки клавиш «enter» и «tab», работа с мышью, функционирование клавиш-акселераторов и полное соответствие индустриальным стандартам);

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

 

3.5.2.5. Профилирование производительности

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

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

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

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

 

 

3.5.2.6. Нагрузочное тестирование

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

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

 

3.5.2.7. Стрессовое тестирование

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

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

Используются тесты, созданные для нагрузочного тестирования и тестирования производительности;

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

 

3.5.2.8. Объемное тестирование

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

Проверяется правильность функционирования объекта тестирования при следующих сценариях:

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

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

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

Используются тесты, созданные для нагрузочного тестирования и тестирования производительности;

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

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

 

3.5.2.9. Тестирование управления доступом. Тестирование безопасности

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

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

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

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

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

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

Цель тестирования: (безопасность на уровне приложения) проверить, что пользователь может обращаться только к тем функциям или данным, к которым он имеет доступ.

(Безопасность на уровне системы). Проверить, что только тем пользователям, которые вошли в систему (приложение), разрешено проводить различные операции.

Определяется список пользователей и функции (или данные) к которым каждый имеет доступ имеется доступ;

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

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

 

3.5.2.10. Тестирование восстановления после сбоев

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

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

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

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

Следующие типы состояний должны быть учтены при составлении тестов:

сбой питания на клиенте и сервере;

коммуникационный сбой через сетевой сервер;

потеря питания в устройствах DASD;

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

неправильный ключ или указатель базы данных;

неправильный или поврежденный элемент в базе.

Для этого вида тестирования используются функциональные тесты и тесты бизнесциклов;

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

выключить питание компьютера;

сымитировать обрыв в сети.

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

3.5.2.11. Конфигурационное тестирование

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

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

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

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

Цель тестирования: проверить объект тестирования на совместимость с объявленным в спецификации оборудованием, операционными системами и программными продуктами третьих фирм.

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

 

3.5.2.12. Инсталляционное тестирование

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

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

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

новая инсталляция, новая машина, не инсталлировалась на нее ранее;

обновление существующей версии (переинсталляция);

обновление со старой версии (апгрейд)

попытка установки старой версии поверх новой.

 

 

 

Загрузка...