Цикломатическая сложность в тестировании программного обеспечения на примере
⚡ Умное резюме
Цикломатическая сложность — это метрика программного обеспечения, разработанная Томасом Маккейбом в 1976 году, которая подсчитывает количество независимых путей в программе. Она рассчитывается на основе графа потока управления и показывает количество тестовых случаев, необходимых для полного покрытия ветвей.

Что такое цикломатическая сложность Маккейба?
Цикломатическая сложность в тестировании программного обеспечения — это метрика тестирования, используемая для измерения сложности программы. Это количественная мера независимых путей в исходном коде программы. Цикломатическая сложность может быть рассчитана с использованием графов потоков управления или относительно функций, модулей, методов или классов в программе.
Независимый путь определяется как путь, имеющий хотя бы одно ребро, которое ранее не было пройдено ни на одном другом пути.
Эта метрика была разработана Томасом Дж. Маккейбом в 1976 году и основана на представлении потока управления программой. Поток управления изображает программу в виде графа, состоящего из узлов и ребер.
На графике узлы представляют задачи обработки, а ребра представляют поток управления между узлами.
Обозначение графа потока для программы
Нотация графа потока для программы определяет несколько узлов, соединенных ребрами. Ниже приведены блок-схемы для таких операторов, как if-else, While, Until и нормальная последовательность выполнения.
Как вычислить цикломатическую сложность
Математическое представление:
Математически это набор независимых путей, проходящих через графическую диаграмму. Code Сложность программы можно определить по формуле:
V(G) = E - N + 2
Где,
E – Количество ребер
N – количество узлов
V (G) = P + 1
Где P = количество узлов предикатов (узел, содержащий условие)
Пример -
i = 0; n=4; //N-Number of nodes present in the graph while (i<n-1) do j = i + 1; while (j<n) do if A[i]<A[j] then swap(A[i], A[j]); end do; j=j+1; end do;
График потока для этой программы будет
Математически вычисляя,
- В(Г) = 9 – 7 + 2 = 4
- V(G) = 3 + 1 = 4 (Узлы условий — это узлы 1,2, 3 и XNUMX)
Базисный наборчетыре независимых пути выполнения:
- 1, 7
- 1, 2, 6, 1, 7
- 1, 2, 3, 4, 5, 2, 6, 1, 7
- 1, 2, 3, 5, 2, 6, 1, 7
Свойства цикломатической сложности
Ниже приведены свойства цикломатической сложности:
- V(G) — максимальное количество независимых путей в графе
- В (Г) >= 1
- G будет иметь один путь, если V (G) = 1
- Распространенное правило — поддерживать значение V(G) на уровне 10 или ниже для одного модуля.
Как эта метрика полезна для тестирования программного обеспечения
Базовое тестирование путей — это один из методов «белого ящика», гарантирующий выполнение как минимум одного оператора во время тестирования. Оно проверяет каждый линейно независимый путь через программу, что означает... Количество необходимых тестовых случаев равно цикломатической сложности программы..
Эта метрика полезна из-за свойств цикломатической сложности (M) –
- M может быть количеством тестовых примеров для достижения покрытия ветвей (верхняя граница).
- M может быть количеством путей через графы. (Нижняя граница)
Рассмотрим этот пример –
If (Condition 1) Statement 1 Else Statement 2 If (Condition 2) Statement 3 Else Statement 4
Цикломатическая сложность для этой программы составит 8-7+2=3.
Поскольку сложность рассчитана как 3, для полного покрытия пути для приведенного выше примера необходимы три тестовых примера.
Шаги, которым необходимо следовать
Для расчета цикломатической сложности и разработки тестовых примеров необходимо выполнить следующие шаги.
Шаг 1 – Построение графа с узлами и ребрами из кода
Шаг 2 – Идентификация независимых путей
Шаг 3 – Расчет цикломатической сложности
Шаг 4 – Разработка тестовых случаев
После того как базовый набор сформирован, ТЕСТОВЫЕ СЛУЧАИ должен быть написан для выполнения всех путей.
Подробнее о В (G)
Цикломатическую сложность можно рассчитать вручную, если программа небольшая. Автоматизированные инструменты необходимо использовать, если программа очень сложна, поскольку она включает в себя больше потоковых графов. На основании числа сложности команда может сделать вывод о действиях, которые необходимо предпринять для измерения.
В следующей таблице представлен обзор показателя сложности и соответствующего значения v (G):
| Сложность Число | Смысл |
|---|---|
| 1 - 10 |
Структурированный и хорошо написанный код Высокая проверяемость Затраты и усилия меньше. |
| 11 - 20 |
Сложный код Средняя проверяемость Затраты и усилия средние. |
| 21 - 40 |
Очень сложный код Низкая тестируемость Затраты и усилия высоки. |
| > 40 |
Совсем не проверяемый Очень высокие затраты и усилия. |
Инструменты для расчета цикломатической сложности
Доступно множество инструментов для определения сложности приложения. Некоторые инструменты расчета сложности используются для конкретных технологий. Сложность можно определить по количеству точек принятия решения в программе. Точками принятия решения являются операторы if, for, for-each, while, do, catch, case в исходном коде.
Примеры инструментов:
- OCLint – Статический анализатор кода для C и родственных языков.
- SonarQube – Содержит отчеты о цикломатической и когнитивной сложности более чем в 25 языках.
- Visual Studio Code Метрики – Встроенный цикломатический анализ сложности для сборок .NET
- Radon и Lizard – анализаторы сложности командной строки для Python и для многоязычных проектов соответственно.
- GMetrics – Найдите показатели в Java связанные приложения
Применение цикломатической сложности
Цикломатическая сложность может оказаться очень полезной в
- Помогает разработчикам и тестировщикам определять независимые пути выполнения.
- Разработчики могут гарантировать, что все пути были протестированы как минимум один раз.
- Помогает нам больше сосредоточиться на открытых путях.
- Улучшить покрытие кода в Программная инженерия
- Оцените риск, связанный с приложением или программой.
- Использование этих показателей на ранних этапах цикла снижает риск программы.
Как уменьшить цикломатическую сложность
Высокий показатель сложности — это сигнал, а не окончательный вывод. Четыре рефакторинга обеспечивают большую часть снижения сложности, достижимого на практике.
- Extracт метод. Перемещение ветви в отдельную функцию распределяет сложность между двумя модулями. Общая сложность системы остается неизменной, но каждый модуль становится тестируемым независимо.
- Замените цепочку условий поиском. Длинная последовательность условий if-else-if, проверяющая одну и ту же переменную, превращается в карту или переключатель, который сводит множество точек принятия решений к одной.
- Используйте защитные оговорки. Досрочный возврат из-за некорректного ввода устраняет вложенность, создаваемую одним большим блоком if-else, без изменения поведения.
- Замените условные операторы на полиморфизм. В тех случаях, когда условное выражение переключается в зависимости от типа, перемещение каждой ветви в отдельный класс полностью исключает необходимость принятия решения.
Ранее, при V(G) = 4:
if (user != null) { if (user.isActive()) { if (user.hasRole("admin")) { return grantAccess(); } } } return denyAccess();
Затем, при сохранении того же поведения и удалении вложенности:
if (user == null) return denyAccess(); if (!user.isActive()) return denyAccess(); if (!user.hasRole("admin")) return denyAccess(); return grantAccess();
Предупреждение относительно используемой метрики. Цикломатическая сложность оценивает принимаемые решения, а не сложность. Оператор switch с двадцатью простыми вариантами получает 21 балл, но при этом легко читается, в то время как глубоко вложенный блок, оцениваемый в 8 баллов, может быть гораздо сложнее для понимания. Используйте это число для поиска кандидатов на проверку, а не как цель для манипуляций.


.png)
.png)