Complejidad ciclomática en las pruebas de software con un ejemplo

⚡ Resumen inteligente

La complejidad ciclomática es una métrica de software desarrollada por Thomas McCabe en 1976 que contabiliza las rutas independientes que puede seguir un programa. Se calcula a partir de un grafo de flujo de control y proporciona el número de casos de prueba necesarios para una cobertura completa de las ramas.

  • 📐 Dos fórmulas: V(G) = E – N + 2 del gráfico, o V(G) = P + 1 del recuento de puntos de decisión.
  • 🧮 Significado directo: El valor equivale al número máximo de rutas independientes y, por lo tanto, a los casos de prueba necesarios.
  • 🗺️ Base gráfica: Los nodos representan los pasos del procesamiento y las aristas representan el flujo de control entre ellos.
  • 🟢 1 a 10: Código estructurado y bien escrito, con alta capacidad de prueba y bajos costos de mantenimiento.
  • 🟠 21 a 40: Código muy complejo con baja capacidad de prueba, donde la refactorización suele costar menos que las pruebas.
  • 🛠️ Estampación: SonarQube, Visual Studio Code Metrics, Radon y Lizard lo calculan automáticamente.

Complejidad ciclomática en pruebas de software

¿Qué es la complejidad ciclomática de McCabe?

Complejidad ciclomática en pruebas de software es una métrica de prueba que se utiliza para medir la complejidad de un programa de software. Es una medida cuantitativa de las rutas independientes en el código fuente de un programa de software. La complejidad ciclomática se puede calcular mediante gráficos de flujo de control o con respecto a funciones, módulos, métodos o clases dentro de un programa de software.

La ruta independiente se define como una ruta que tiene al menos un borde que no ha sido atravesado antes en ninguna otra ruta.

Esta métrica fue desarrollada por Thomas J. McCabe en 1976 y se basa en una representación del flujo de control del programa. El flujo de control representa un programa como un gráfico que consta de nodos y aristas.

En el gráfico, los nodos representan tareas de procesamiento, mientras que los bordes representan el flujo de control entre los nodos.

La complejidad ciclomática de McCabe

Notación de grafo de flujo para un programa

La notación de gráfico de flujo para un programa define varios nodos conectados a través de los bordes. A continuación se muestran diagramas de flujo para declaraciones como if-else, While, Until y la secuencia normal de flujo.

Notación de gráfico de flujo para un programa.

Cómo calcular la complejidad ciclomática

Representación matemática:

Matemáticamente, es un conjunto de caminos independientes a través del diagrama gráfico. Code La complejidad del programa se puede definir utilizando la fórmula:

V(G) = E - N + 2

Dónde,

E – Número de aristas

N – Número de nodos

V (G) = P + 1

Donde P = Número de nodos predicados (nodo que contiene condición)

Ejemplo

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;

El gráfico de flujo para este programa será

Calcular la complejidad ciclomática

Calcular matemáticamente,

  • V(G) = 9 – 7 + 2 = 4
  • V(G) = 3 + 1 = 4 (Los nodos de condición son 1,2, 3 y XNUMX nodos)

Conjunto base, las cuatro rutas de ejecución independientes:

  • de 1
  • 1, 2, 6, 1, 7
  • 1, 2, 3, 4, 5, 2, 6, 1, 7
  • 1, 2, 3, 5, 2, 6, 1, 7

Propiedades de la complejidad ciclomática

Las siguientes son las propiedades de la complejidad ciclomática:

  1. V (G) es el número máximo de caminos independientes en el gráfico.
  2. V (G) >=1
  3. G tendrá un camino si V (G) = 1
  4. Una pauta comúnmente utilizada es mantener V(G) en 10 o menos para un solo módulo.

Cómo esta métrica resulta útil para las pruebas de software

Las pruebas de ruta base son una técnica de caja blanca y garantizan la ejecución de al menos una instrucción durante las pruebas. Verifican cada ruta linealmente independiente a través del programa, lo que significa que El número de casos de prueba necesarios es igual a la complejidad ciclomática del programa..

Esta métrica es útil debido a las propiedades de la complejidad ciclomática (M):

  1. M puede ser el número de casos de prueba para lograr la cobertura de sucursales (límite superior)
  2. M puede ser el número de caminos a través de los gráficos. (Límite inferior)

Considere este ejemplo:

If (Condition 1)
Statement 1

Else
Statement 2

If (Condition 2)
Statement 3

Else
Statement 4

La complejidad ciclomática para este programa será 8-7+2=3.

Como la complejidad se ha calculado como 3, son necesarios tres casos de prueba para cubrir la ruta completa para el ejemplo anterior.

Pasos a seguir

Se deben seguir los siguientes pasos para calcular la complejidad ciclomática y el diseño de casos de prueba.

Paso 1 – Construcción de grafo con nodos y aristas a partir del código.

Paso 2 – Identificación de caminos independientes

Paso 3 – Cálculo de complejidad ciclomática

Paso 4 – Diseño de Casos de Prueba

Una vez formado el conjunto básico, CASOS DE PRUEBA debe escribirse para ejecutar todas las rutas.

Más sobre V (G)

La complejidad ciclomática se puede calcular manualmente si el programa es pequeño. Si el programa es muy complejo, se deben utilizar herramientas automatizadas, ya que esto implica más gráficos de flujo. En función del número de complejidad, el equipo puede sacar conclusiones sobre las acciones que se deben tomar para medir el rendimiento.

La siguiente tabla ofrece una visión general del número de complejidad y el significado correspondiente de v (G):

Número de complejidad Significado
1 a 10

Código estructurado y bien escrito

Alta capacidad de prueba

El costo y el esfuerzo son menores.

11 a 20

Código complejo

Capacidad de prueba media

El costo y el esfuerzo son moderados.

21 a 40

Código muy complejo

Baja capacidad de prueba

El costo y el esfuerzo son elevados.

> 40

Nada comprobable

Costo y esfuerzo muy elevados

Herramientas para calcular la complejidad ciclomática

Existen muchas herramientas disponibles para determinar la complejidad de una aplicación. Algunas herramientas de cálculo de complejidad se utilizan para tecnologías específicas. La complejidad se puede determinar por la cantidad de puntos de decisión en un programa. Los puntos de decisión son las instrucciones if, for, for-each, while, do, catch y case en un código fuente.

Ejemplos de herramientas son

  • OCLint – Analizador de código estático para C y lenguajes relacionados.
  • SonarQube – Informa sobre la complejidad ciclomática y cognitiva en más de 25 idiomas.
  • Visual Studio Code Métricas: análisis de complejidad ciclomática integrado para ensamblados .NET
  • Radon y Lizard: analizadores de complejidad de línea de comandos para Python y para proyectos multilingües respectivamente
  • GMetrics – Encuentra métricas en Java aplicaciones relacionadas

Usos de la complejidad ciclomática

La complejidad ciclomática puede resultar muy útil en

  • Ayuda a los desarrolladores y evaluadores a determinar ejecuciones de rutas independientes
  • Los desarrolladores pueden asegurar que todas las rutas se han probado al menos una vez.
  • Nos ayuda a centrarnos más en los caminos descubiertos.
  • Mejorar la cobertura del código en Ingeniería de Software
  • Evaluar el riesgo asociado con la aplicación o programa.
  • El uso de estas métricas al principio del ciclo reduce el riesgo del programa.

Cómo reducir la complejidad ciclomática

Un número de complejidad elevado es una señal, no un veredicto. Cuatro refactorizaciones representan la mayor parte de la reducción que se puede lograr en la práctica.

  • Extracmétodo t. Trasladar una rama a su propia función divide la complejidad entre dos módulos. La complejidad total del sistema permanece inalterada, pero cada unidad se puede probar de forma independiente.
  • Reemplazar una cadena condicional con una búsqueda. Una larga estructura condicional if-else-if que prueba la misma variable se convierte en un mapa o un switch, que condensa muchos puntos de decisión en uno solo.
  • Utilice cláusulas de protección. Devolver un valor de forma anticipada ante una entrada no válida elimina el anidamiento que crea un único bloque if-else grande, sin cambiar el comportamiento.
  • Reemplazar las condicionales con polimorfismo. Cuando una condición cambia según el tipo, al mover cada rama a su propia clase se elimina por completo la decisión.

Antes, con V(G) = 4:

if (user != null) {
    if (user.isActive()) {
        if (user.hasRole("admin")) {
            return grantAccess();
        }
    }
}
return denyAccess();

Después, con el mismo comportamiento y sin anidamiento:

if (user == null) return denyAccess();
if (!user.isActive()) return denyAccess();
if (!user.hasRole("admin")) return denyAccess();
return grantAccess();

Una advertencia sobre la métrica. La complejidad ciclomática contabiliza las decisiones, no la dificultad. Una sentencia switch con veinte casos simples obtiene una puntuación de 21 y, sin embargo, es fácil de leer, mientras que un bloque anidado con una puntuación de 8 puede ser mucho más difícil de entender. Utilice este número para identificar candidatos para su revisión, no como un objetivo para manipular.

Preguntas Frecuentes

La pauta general es de diez o menos módulos. Entre 11 y 20, el código es complejo pero manejable. Por encima de 20, la capacidad de prueba disminuye drásticamente, y por encima de 40, el módulo generalmente se considera imposible de probar tal como está escrito.

Ambos métodos dan el mismo resultado. P + 1 es más rápido para el cálculo manual porque solo se cuentan los puntos de decisión. E – N + 2 es el método que utilizan las herramientas, ya que estas ya construyen el grafo de flujo de control.

No necesariamente. La complejidad ciclomática tiene en cuenta las decisiones, no la dificultad, por lo que un switch plano con veinte casos simples obtiene una puntuación alta y, a la vez, es fácil de leer. Considere el número como una indicación para la revisión.

Lo combinan con la frecuencia de los cambios y el historial de defectos para clasificar qué módulos conllevan mayor riesgo, dirigiendo los esfuerzos de revisión y prueba al código con mayor probabilidad de fallar.

Sí. Los asistentes de IA proponen cláusulas de protección, por ejemplotracMétodos modificados y tablas de búsqueda que reducen el recuento. Verifique el comportamiento con el conjunto de pruebas existente, ya que una refactorización que cambie la lógica anula el propósito.

Resumir este post con: