Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Технологии разработки ПО. Лабораторный практикум

.pdf
Скачиваний:
0
Добавлен:
08.09.2026
Размер:
2 Мб
Скачать
NP – максимально возможное количество связей между N методами:
NP = N (N – 1) / 2;
NDC – количество прямых связей между методами;
NIC – количество прямых и косвенных связей между ме-
тодами. работе рассматривается одна из методик структур­ного тестирования, разработанная Томасом Дж. МакКейбом (Thomas J. McCabe) – тестирование базового пути.
Алгоритм применения методики заключается в следующем.
1. Для заданной программы строится потоковый граф.
2. По потоковому графу определяется цикломатическая
сложность программы и выделяется базовое множество линей­но независимых маршрутов.
3. Разрабатываются тесты (наборы входных данных и ожи­даемых результатов), обеспечивающие однократную проверку каждого маршрута базового множества. Количество таких те­стов равно цикломатической сложности программы.
4. Осуществляется прогон программы по разработанным тестам, при этом реально полученные результаты сопоставля­ются с ожидаемыми.
Потоковый граф (control-flow graph) – множество всех возможных путей выполнения программы, представленное в виде направленного графа.
Цикломатическая сложность (сyclomatic complexity) – ко­личество линейно независимых маршрутов в потоковом графе.
Линейно независимый маршрут (linearly independent path) – путь, включающий по крайней мере одно ребро, не находящееся ни в одном из других путей.
При построении потокового графа следует придерживаться следующих правил.
1. Потоковый граф должен иметь строго один входной узел и строго один выходной узел. Граф, не имеющий входного узла, описывает недостижимый код. Граф, не имеющий выходного узла, описывает бесконечный цикл.
2. Последовательный участок программного кода, не со­держащий операторов ветвления и цикла, а также меток пере-
41
хода из других участков кода, представляется простым узлом потокового графа, имеющим строго одну исходящую дугу.
3. Оператор ветвления или цикла преобразуется в преди- катный узел, имеющий строго две исходящие дуги.
4. Составные условия и множественные ветвления преоб­разуются в цепочку предикатных узлов.
Пример корректного потокового графа приведен на рис. 5.1.
Рис. 5.1. Потоковый граф программы: узел 1 является вход-
ным; узел 7 – выходным; узлы 2, 3, 5 – предикатные
Цикломатическая сложность V(G) графа G, имеющего e дуг
и n узлов, может быть определена по формуле
V(G) = e – n + 2.
Второй способ определения цикломатической сложности –
по числу p предикатных узлов графа G:
V(G) = p + 1.
Третий способ: цикломатическая сложность равна количе­ству R регионов графа. На рис. 5.2 показаны четыре региона графа – R
, R2, R3, R4.
1
42
Рис. 5.2. Регионы потокового графа
Цикломатическая сложность потокового графа равна
V(G) = e – n + 2 = 9 – 7 + 2 = 4;
V(G) = p + 1 = 3 + 1 = 4;
V(G) = R = 4.
Следовательно, потоковый граф имеет 4 базовых маршрута (табл. 5.1).
Таблица 5.1
Номер маршрута Маршрут (последовательность узлов)
1 1–2–4–7 2 1–2–3–6–7 3 1–2–3–5–7 4 1–2–3–5–2–4–7
Номера маршрутов, соответствующие им входные данные, условия запуска и ожидаемые результаты заносят в первые три столбца таблицы тестирования (табл. 5.2).
43
Таблица 5.2
Номер
Входные данные
и условия запуска
Ожидаемый
результат
Полученный
результат
Вывод
После прогона программы по всем маршрутам в четвертый столбец заносят полученные результаты, а в пятый – вывод («тест пройден» / «тест не пройден»).
5.3. Порядок выполнения работы
1. Получить у преподавателя свой вариант задания.
2. Реализовать метод класса, решающий поставленную за-
дачу.
3. Построить потоковый граф метода, определить его ци-
кломатическую сложность.
4. Выделить базовые маршруты, разработать тестовые ва-
рианты.
5. Осуществить тестирование программы и заполнить
табл. 5.2.
6. Оформить отчет о выполненной работе.
5.4. Пример выполнения работы
Метод класса, который необходимо протестировать, должен складывать, вычитать, умножать или делить два целых числа, введенных с клавиатуры, и выводить результат на экран кон­соли.
На листинге представлен код метода.
25: void Calculator () 26: { 27: Console.Write(«Введитех:“); 28: int x = Convert.ToInt32 (Console.ReadLine ()); 29: Console.Write(«Выберитеоперацию[+,–,*,/]:“); 30: char operation = Convert.ToChar (Console.ReadLine ()); 31: Console.Write(«Введитеy:“); 32: int y = Convert.ToInt32 (Console.ReadLine ()); 33: string s = x.ToString () + operation + y.ToString () +”=”;
44
34: stringresult=“”; 35: if(operation==‘/’&&y==0) 36: { 37: result=«ошибкаделениянаноль»; 38: } 39: else 40: { 41: switch (operation) 42: { 43: case‘+’:result=(x+y).ToString();break; 44: case‘-’:result=(x–y).ToString();break; 45: case‘*’:result=(x–y).ToString();break; 46: case‘/’:result=(x/y).ToString();break; 47: default:result=«ошибочнаяоперация»;break; 48: } 49: } 50: Console.WriteLine (s + result); 51: Console.ReadKey (); 52: }
Код преобразуется в потоковый граф, приведенный на рис. 5.3.
Линейные участки кода преобразуются в узлы: 1 (строки 1…10), 7 (строки 12…14), 5 (строка 19), 8 (строка 20), 10 (стро­ка 21), 12 (строка 22), 13 (строка 23), 14 (строки 24…28).
Условный оператор if в строке 11 является составным (про­веряется два независимых условия), поэтому он преобразуется в два предикатных узла – 2 и 4.
Оператор множественного выбора switch преобразуется це­почку из четырех предикатных узлов: 3, 6, 9, 11.
Цикломатическая сложность метода:
V (Calculator) = e – n + 2 = 19–14 + 2 = 7;
V (Calculator) = p + 1 = 6 + 1 = 7;
V (Calculator) = R = 7.
Выделим базовые маршруты (табл. 5.3).
45
Рис. 5.3. Потоковый граф метода Calculator
Таблица 5.3
Номер
маршрута
1 1–2–4–7–14 2 1–2–3–5–14 3 1–2–4–3–5–14 4 1–2–3–6–8–14 5 1–2–3–6–9–10–14 6 1–2–3–6–9–11–12–14 7 1–2–3–6–9–11–13–14
Маршрут (последовательность узлов)
Подберем значения входных данных под каждый из марш­рутов и определим ожидаемый результат (табл. 5.4).
46
Таблица 5.4
Номер
теста
1 5 / 0 Ошибка деления на ноль 2 24 / 12 2 3 0 + 3 3 4 1 10 –9 5 4 * –6 –24 6 15 / 2 7,5 7 250 % 8 Ошибочная операция
Входные данные
x operation y
Ожидаемый результат
Внесем данные в левую часть таблицы тестирования и вы­полним тесты, заполняя правую часть. В итоге таблица тести­рования примет вид табл. 5.5.
Таблица 5.5
Но-
мер
1 5 / 0 Ошибка деле-
2 24 / 12 2 2 + 3 0 + 3 3 3 + 4 1 10 –9 –9 + 5 4 * –6 –24 10 – 6 15 / 2 7,5 7 – 7 250 % 8 Ошибочная
Входные данные
x operation y
Ожидаемый
результат
ния на ноль
операция
Полученный
результат
Ошибка деле-
ния на ноль
Ошибочная
операция
Вывод
+
+
Тесты 5 и 6 не пройдены. Находим в табл. 5.3 узлы, отли­чающие маршруты 5 и 6 от остальных маршрутов множества. Это узлы 10 и 12, соответствующие строкам кода 21 и 22. Ана­лизируя эти строки, находим причины ошибок:
– в строке 21 выполняется операция вычитания вместо ум-
ножения;
– в строке 22 выполняется целочисленное деление.
5.5. Вопросы для самоконтроля
1. Какой из трех способов определения цикломатической сложности позволяет рассчитать ее без построения потокового графа, имея только код программы?
47
2. Какие узлы в строке 3 табл. 5.3 можно заменить на дру­гие, не разрушив базовый набор?
3. Какие из значений входных данных в табл. 5.4 можно изменить, сохранив при этом маршруты?
4. Почему оператор switch отображается в несколько узлов потокового графа?
5. Как таблица результатов тестирования помогает лока­лизовать источник ошибки?
48
Лабораторная работа № 6
«ФУНКЦИОНАЛЬНОЕ
ТЕСТИРОВАНИЕ»
6.1. Цель работы
Получение практических навыков в тестировании про-
грамм по принципу «черного ящика».
6.2. Теоретический минимум
Функциональное тестирование (тестирование «черного ящика») позволяет получить наборы входных данных, обе­спечивающие исчерпывающую проверку программы на соот­ветствие функциональным требованиям. Программа рассма­тривается здесь как «черный ящик», внутренняя реализация которого скрыта, доступны для исследования лишь информа­ционные входы и выходы (рис. 6.1).
Рис. 6.1. Представление программы в виде «черного ящика»
Проведение исчерпывающего тестирования предполага­ет выполнение программы на всех возможных комбинациях входных данных и их последовательностей. Очевидно, что почти для всех реальных программ проведение исчерпываю­щего тестирования невозможно. В большинстве случаев под­бирают разумное количество тестов, позволяющих с большой вероятностью выявить:
49
– при каких наборах входных данных проявляются анома-
лии в работе программы;
– какие наборы выходных данных демонстрируют дефек-
ты в работе программы.
Рассмотрим три общепринятые методики получения те­стовых данных: эквивалентное разбиение, анализ граничных значений и граф причинно-следственных связей.
6.2.1. Методика эквивалентного разбиения
Методика предполагает разбиение области входных данных на конечное число групп – классов эквивалентности.
Класс эквивалентности (equivalence class) – это такие ком­бинации наборов входных данных, обрабатывая которые про­грамма ведет себя одинаково.
Достаточно протестировать программу на одном наборе входных данных, чтобы судить о ее поведении на всем классе эквивалентности. Таким образом, разработав по одному тесту для каждого класса, можно получить набор тестов, обеспечи­вающих «разумное» тестирование.
Классы эквивалентности формируются согласно специфи­кациям по следующим правилам.
1. Если входной параметр x может принимать значения на
отрезке n…m, то формируют три класса:
– допустимый: x {nm}; – недопустимый: x < n; – недопустимый: x > m.
2. Если входной параметр x может принимать значение из
множества {n, m, p}, то формируют два класса:
– допустимый: x {n,m,p}; – недопустимый: x {n,m,p}.
3. Если есть основания считать, что различные элементы одного класса могут обрабатываться программой по-разному, то такой класс разбивается на меньшие классы эквивалентно­сти.
Определив классы эквивалентности для всех входных па­раметров, получают перечень допустимых и недопустимых классов и заносят их в табл. 6.1.
50
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]