Cobertura de código

AjustarCompartirImprimirCitar
Metric for source code testing

En informática, la cobertura de prueba es una medida porcentual del grado en que se ejecuta el código fuente de un programa cuando se ejecuta un conjunto de pruebas en particular. Un programa con una alta cobertura de prueba tiene una mayor parte de su código fuente ejecutado durante la prueba, lo que sugiere que tiene menos posibilidades de contener errores de software no detectados en comparación con un programa con baja cobertura de prueba. Se pueden usar muchas métricas diferentes para calcular la cobertura de la prueba. Algunos de los más básicos son el porcentaje de subrutinas de programa y el porcentaje de declaraciones de programa llamadas durante la ejecución del conjunto de pruebas.

La cobertura de pruebas fue uno de los primeros métodos inventados para las pruebas sistemáticas de software. La primera referencia publicada fue de Miller y Maloney en Comunicaciones de la ACM, en 1963.

Criterios de cobertura

Para medir qué porcentaje de código ha sido ejecutado por un conjunto de pruebas, se utilizan uno o más criterios de cobertura. Por lo general, se definen como reglas o requisitos que debe satisfacer un conjunto de pruebas.

Criterios básicos de cobertura

Existen varios criterios de cobertura, pero los principales son:

  • Cobertura de funciones– ¿Se ha llamado cada función (o subrutina) en el programa?
  • Cobertura por declaración– ¿Se ha ejecutado cada declaración en el programa?
  • Cobertura de bordes– ¿Se ha ejecutado cada borde en el gráfico de flujo de control?
    • Cobertura de las oficinas– ¿Se ha ejecutado cada rama (también llamada DD-path) de cada estructura de control (como en declaraciones de caso y de caso). Por ejemplo, dado un si declaración, tienen ambos verdadero y falso ¿Las ramas fueron ejecutadas? (Este es un subconjunto de cobertura de bordes.)
  • Cobertura de condiciones– ¿Se ha evaluado cada subexpresión booleana tanto a la verdad como a la falsa? (También llamada cobertura predicada.)

Por ejemplo, considere la siguiente función C:

int Foo ()int x, int Sí.){} int z = 0; si ()x  0) " ()Sí.  0) {} z = x; } retorno z;}

Suponga que esta función es parte de un programa más grande y este programa se ejecutó con algún conjunto de pruebas.

  • Cobertura de funciones estará satisfecho si, durante esta ejecución, la función foo fue llamado al menos una vez.
  • Cobertura por declaración para esta función será satisfecha si fue llamado por ejemplo como foo(1,1), porque en este caso, cada línea en la función sería ejecutada, incluyendo z = x;.
  • Cobertura de las oficinas estará satisfecho con las pruebas llamando foo(1,1) y foo(0,1) porque, en el primer caso, ambos if condiciones se cumplen y z = x; se ejecuta, mientras que en el segundo caso, la primera condición, (x>0), no está satisfecho, lo que impide la ejecución de z = x;.
  • Cobertura de condiciones estará satisfecho con las pruebas que llaman foo(1,0), foo(0,1), y foo(1,1). Estos son necesarios porque en los primeros casos, (x>0) se evalúa true, mientras que en el segundo, se evalúa false. Al mismo tiempo, el primer caso hace (y>0) false, el segundo caso no evalúa (y>0) (por la perezosa evaluación del operador booleano), el tercer caso lo hace true.

La cobertura de condición no implica necesariamente cobertura de sucursal. Por ejemplo, considere el siguiente fragmento de código:

si a y b entonces

La cobertura de la condición se puede satisfacer mediante dos pruebas:

  • a=true, b=false
  • a=false, b=true

Sin embargo, este conjunto de pruebas no satisface la cobertura de sucursales ya que ninguno de los casos cumplirá la condición if.

La inyección de fallas puede ser necesaria para garantizar que todas las condiciones y ramas del código de manejo de excepciones tengan una cobertura adecuada durante las pruebas.

Condición modificada/cobertura de decisión

Una combinación de cobertura de funciones y cobertura de sucursales a veces también se denomina cobertura de decisiones. Este criterio requiere que cada punto de entrada y salida en el programa haya sido invocado al menos una vez, y cada decisión en el programa haya tomado todos los resultados posibles al menos una vez. En este contexto, la decisión es una expresión booleana que comprende condiciones y cero o más operadores booleanos. Esta definición no es la misma que la cobertura de sucursal, sin embargo, el término cobertura de decisión a veces se usa como sinónimo.

Cobertura de condición/decisión requiere que se cumplan tanto la cobertura de decisión como la de condición. Sin embargo, para las aplicaciones críticas para la seguridad (como el software de aviónica), a menudo se requiere que se cumpla la cobertura modificada de condición/decisión (MC/DC). Este criterio amplía los criterios de condición/decisión con requisitos de que cada condición debe afectar el resultado de la decisión de forma independiente.

Por ejemplo, considere el siguiente código:

si ()a o b) y c entonces

Los criterios de condición/decisión se cumplirán mediante el siguiente conjunto de pruebas:

  • a=true, b=true, c=true
  • a=falso, b=false, c=false

Sin embargo, el conjunto de pruebas anterior no satisfará la cobertura de decisión/condición modificada, ya que en la primera prueba, el valor de 'b' y en la segunda prueba el valor de 'c' no influiría en la salida. Por lo tanto, se necesita el siguiente conjunto de pruebas para satisfacer MC/DC:

  • a=falso, b=true, c=falso
  • a=falso, b=verdadero, c=verdadero
  • a=falso, b=falso, c=true
  • a=verdadero, b=false, c=verdadero

Cobertura de condiciones múltiples

Este criterio requiere que se prueben todas las combinaciones de condiciones dentro de cada decisión. Por ejemplo, el fragmento de código de la sección anterior requerirá ocho pruebas:

  • a=falso, b=false, c=false
  • a=falso, b=falso, c=true
  • a=falso, b=true, c=false
  • a=falso, b=true, c=true
  • a=true, b=false, c=false
  • a=true, b=false, c=true
  • a=true, b=true, c=false
  • a=true, b=true, c=true

Cobertura del valor del parámetro

Cobertura de valor de parámetro (PVC) requiere que en un método que toma parámetros, se consideren todos los valores comunes para dichos parámetros. La idea es que se prueben todos los valores posibles comunes para un parámetro. Por ejemplo, los valores comunes para una cadena son: 1) nulo, 2) vacío, 3) espacio en blanco (espacio, tabuladores, nueva línea), 4) cadena válida, 5) cadena no válida, 6) cadena de un solo byte, 7) doble cadena de bytes. También puede ser apropiado usar cadenas muy largas. Si no se prueba cada valor de parámetro posible, se puede generar un error. Probar solo uno de estos podría dar como resultado una cobertura de código del 100 %, ya que se cubre cada línea, pero como solo se prueba una de las siete opciones, solo hay un 14,2 % de PVC.

Otros criterios de cobertura

Existen otros criterios de cobertura, que se utilizan con menos frecuencia:

  • Codigo lineal Secuencia y Salto (LCSAJ) cobertura a.k.a. Cobertura JJ-Path– ¿todo LCSAJ/JJ-path ha sido ejecutado?
  • Cobertura del camino– ¿Se ha ejecutado toda ruta posible a través de una parte determinada del código?
  • Cobertura de entrada y salida– ¿Se ha ejecutado toda posible llamada y retorno de la función?
  • Cobertura de bucle– ¿Se ha ejecutado todo lo posible cero veces, una vez y más de una vez?
  • Cobertura del Estado– ¿Se ha alcanzado y explorado cada estado en una máquina de estado finito?
  • Cobertura de la corriente de datos– ¿Se ha alcanzado y explorado cada definición variable y su uso?

A menudo se requiere que las aplicaciones confiables o críticas para la seguridad demuestren el 100 % de alguna forma de cobertura de prueba. Por ejemplo, el estándar ECSS-E-ST-40C exige una cobertura del 100% de declaraciones y decisiones para dos de cuatro niveles de criticidad diferentes; para los demás, los valores de cobertura objetivo quedan a negociación entre proveedor y cliente. Sin embargo, el establecimiento de valores objetivo específicos -y, en particular, el 100%- ha sido criticado por los profesionales por varias razones (cf.) Martin Fowler escribe: "Sospecharía al 100 % de cualquier cosa; olería a que alguien escribe pruebas para hacer felices los números de cobertura, pero sin pensar en lo que está haciendo".

Algunos de los criterios de cobertura anteriores están conectados. Por ejemplo, la cobertura de ruta implica cobertura de decisión, declaración y entrada/salida. Cobertura de decisión implica cobertura de declaración, porque cada declaración es parte de una rama.

La cobertura completa del camino, del tipo descrito anteriormente, es generalmente poco práctico o imposible. Cualquier módulo con una sucesión de n{displaystyle n} decisiones en ella pueden tener hasta 2n{displaystyle 2^{n} caminos dentro de ella; los constructos de bucle pueden resultar en un número infinito de caminos. Muchos caminos también pueden ser infeables, ya que no hay entrada al programa bajo prueba que pueda hacer que ese camino particular sea ejecutado. Sin embargo, un algoritmo de uso general para identificar caminos infeasibles ha sido demostrado como imposible (como un algoritmo podría ser utilizado para resolver el problema de detención). Las pruebas de la ruta de la base son, por ejemplo, un método para lograr la cobertura completa de las ramas sin alcanzar la cobertura completa de la ruta.

Los métodos para las pruebas prácticas de cobertura de ruta intentan identificar clases de rutas de código que difieren solo en el número de ejecuciones de bucle y lograr "ruta básica" cobertura, el probador debe cubrir todas las clases de ruta.

En la práctica

El software de destino se crea con opciones o bibliotecas especiales y se ejecuta en un entorno controlado, para asignar cada función ejecutada a los puntos de función en el código fuente. Esto permite probar partes del software de destino a las que rara vez o nunca se accede en condiciones normales, y ayuda a garantizar que se hayan probado las condiciones más importantes (puntos de función). El resultado resultante se analiza luego para ver qué áreas del código no se han ejercitado y las pruebas se actualizan para incluir estas áreas según sea necesario. En combinación con otros métodos de cobertura de pruebas, el objetivo es desarrollar un conjunto de pruebas de regresión rigurosas pero manejables.

Al implementar políticas de cobertura de prueba dentro de un entorno de desarrollo de software, se debe considerar lo siguiente:

  • ¿Cuáles son los requisitos de cobertura para la certificación del producto final y si es así qué nivel de cobertura de prueba es necesario? El nivel típico de progresión del rigor es el siguiente: Declaración, Rama/Decisión, Condición Modificada/Cobertura de Decisión (MC/DC), LCSAJ (Secuencia y Salto del Código de la Luz)
  • ¿Se medirá la cobertura contra pruebas que verifiquen los requisitos exigidos en el sistema bajo prueba (DO-178B)?
  • ¿El código de objeto se genera directamente rastreable a las declaraciones de código fuente? Ciertas certificaciones (es decir, DO-178B Nivel A) requieren cobertura a nivel de montaje si este no es el caso: "Entonces, la verificación adicional debe realizarse en el código de objeto para establecer la corrección de tales secuencias de código generadas" (DO-178B) para-6.4.4.2.

Los autores de software pueden ver los resultados de la cobertura de prueba para diseñar pruebas adicionales y conjuntos de entrada o configuración para aumentar la cobertura de funciones vitales. Dos formas comunes de cobertura de prueba son la cobertura de declaración (o línea) y la cobertura de rama (o borde). La cobertura de línea informa sobre la huella de ejecución de las pruebas en términos de qué líneas de código se ejecutaron para completar la prueba. La cobertura de borde informa qué ramas o puntos de decisión de código se ejecutaron para completar la prueba. Ambos informan una métrica de cobertura, medida como un porcentaje. El significado de esto depende de la(s) forma(s) de cobertura que se hayan utilizado, ya que una cobertura de sucursal del 67 % es más completa que una cobertura de estado de cuenta del 67 %.

Por lo general, las herramientas de cobertura de prueba incurren en cálculos y registros además del programa real, lo que ralentiza la aplicación, por lo que, por lo general, este análisis no se realiza en producción. Como era de esperar, hay clases de software que no se pueden someter de manera factible a estas pruebas de cobertura, aunque se puede aproximar un grado de mapeo de cobertura mediante análisis en lugar de pruebas directas.

También hay algunos tipos de defectos que se ven afectados por dichas herramientas. En particular, algunas condiciones de carrera u operaciones sensibles en tiempo real similares pueden enmascararse cuando se ejecutan en entornos de prueba; aunque a la inversa, algunos de estos defectos pueden volverse más fáciles de encontrar como resultado de la sobrecarga adicional del código de prueba.

La mayoría de los desarrolladores de software profesionales utilizan la cobertura C1 y C2. C1 significa cobertura de declaración y C2 cobertura de sucursal o condición. Con una combinación de C1 y C2, es posible cubrir la mayoría de las declaraciones en una base de código. La cobertura de declaraciones también cubriría la cobertura de funciones con cobertura de entrada y salida, bucle, ruta, flujo de estado, flujo de control y flujo de datos. Con estos métodos, es posible lograr una cobertura de código de casi el 100 % en la mayoría de los proyectos de software.

Uso en la industria

La cobertura de las pruebas es una consideración en la certificación de seguridad de los equipos de aviónica. Las pautas por las cuales el equipo de aviónica está certificado por la Administración Federal de Aviación (FAA) se documentan en DO-178B y DO-178C.

La cobertura de la prueba también es un requisito en la parte 6 de la norma de seguridad automotriz ISO 26262 Vehículos de carretera: seguridad funcional.

Contenido relacionado

Transporte en Puerto Rico

ÑU

Bugatti

Más resultados...
Tamaño del texto: