Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Технологии разработки ПО. Лабораторный практикум
.pdf
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: stringresult=“”;
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 ∈ {n…m};
– недопустимый: x < n;
– недопустимый: x > m.
2. Если входной параметр x может принимать значение из
множества {n, m, p}, то формируют два класса:
– допустимый: x ∈ {n,m,p};
– недопустимый: x ∉ {n,m,p}.
3. Если есть основания считать, что различные элементы
одного класса могут обрабатываться программой по-разному,
то такой класс разбивается на меньшие классы эквивалентности.
Определив классы эквивалентности для всех входных параметров, получают перечень допустимых и недопустимых
классов и заносят их в табл. 6.1.
50
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
