Articulo de referencia

Cobertura de código

En ingeniería de software , la cobertura de código , también llamada cobertura de pruebas , es una medida porcentual del grado en que se ejecuta el código fuente de un programa ...

En ingeniería de software , la cobertura de código , también llamada cobertura de pruebas , es una medida porcentual del grado en que se ejecuta el código fuente de un programa cuando se ejecuta un conjunto de pruebas específico . Un programa con alta cobertura de código tiene una mayor cantidad de su código fuente ejecutado durante las pruebas, lo que sugiere que tiene una menor probabilidad de contener errores de software no detectados en comparación con un programa con baja cobertura de código. [ 1 ] [ 2 ] Se pueden utilizar muchas métricas diferentes para calcular la cobertura de pruebas. Algunas de las más básicas son el porcentaje de subrutinas del programa y el porcentaje de instrucciones del programa llamadas durante la ejecución del conjunto de pruebas.

La cobertura de código fue uno de los primeros métodos inventados para las pruebas sistemáticas de software . La primera referencia publicada fue la de Miller y Maloney en Communications of the ACM , en 1963. [ 3 ]

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 . Estos se definen generalmente como reglas o requisitos que un conjunto de pruebas debe cumplir. [ 4 ]

Criterios básicos de cobertura

Existen varios criterios de cobertura, pero los principales son: [ 5 ]

  • Cobertura de funciones : ¿se ha llamado a cada función (o subrutina ) del programa? 
  • Cobertura de instrucciones : ¿se ha ejecutado cada instrucción del programa? 
  • Cobertura de aristas : ¿ se han ejecutado todas las aristas del grafo de flujo de control ? 
    • Cobertura de ramas : ¿ se ha ejecutado cada rama (también llamada ruta DD ) de cada estructura de control (como en las sentencias if y case )? Por ejemplo, dada una sentencia if , ¿se han ejecutado tanto la rama verdadera como la falsa ? (Esto es un subconjunto de la cobertura de aristas ) . 
  • Cobertura de condiciones : ¿ cada subexpresión booleana se ha evaluado como verdadera y falsa? (También llamada cobertura de predicados). 

Por ejemplo, considere la siguiente función en C :

int foo ( int x , int y ) { int z = 0 ; if (( x > 0 ) && ( y > 0 )) { z = x ; } return z ; }

Supongamos que esta función forma parte de un programa más grande y que este programa se ejecutó con un conjunto de pruebas.

  • La cobertura de funciones se considerará satisfecha si, durante esta ejecución, la función foose llamó al menos una vez.
  • La cobertura de sentencias para esta función se satisfará si se llama, por ejemplo, como foo(1,1), porque en este caso, se ejecutaría cada línea de la función, incluyendo z = x;.
  • La cobertura de ramas se satisfará mediante pruebas que llamen a foo(1,1)y foo(0,1)porque, en el primer caso, ifse cumplen ambas condiciones y z = x;se ejecuta, mientras que en el segundo caso, (x>0)no se cumple la primera condición, , lo que impide la ejecución de z = x;.
  • La cobertura de condiciones se satisfará con pruebas que llamen a foo(1,0), foo(0,1), y foo(1,1). Estas son necesarias porque en el primer caso, (x>0)se evalúa como true, mientras que en el segundo, se evalúa como false. Al mismo tiempo, el primer caso hace que (y>0)false, el segundo caso no se evalúa (y>0)(debido a la evaluación perezosa del operador booleano), el tercer caso hace que true.

En los lenguajes de programación que no realizan evaluación de cortocircuito , la cobertura de condiciones no implica necesariamente la cobertura de ramas. Por ejemplo, considere el siguiente fragmento de código Pascal :

si a y b entonces

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

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

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

Puede ser necesario inyectar fallos para garantizar que todas las condiciones y ramas del código de gestión de excepciones tengan una cobertura adecuada durante las pruebas.

Cobertura de condiciones/decisiones modificadas

La combinación de cobertura de funciones y cobertura de ramas también se denomina a veces cobertura de decisiones . Este criterio exige que cada punto de entrada y salida del programa se haya invocado al menos una vez, y que cada decisión del programa haya considerado 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 ramas, [ 6 ] sin embargo, el término cobertura de decisiones se utiliza a veces como sinónimo. [ 7 ]

La cobertura de condiciones/decisiones exige que se cumplan tanto la cobertura de decisiones como la de condiciones. Sin embargo, para aplicaciones críticas para la seguridad (como el software de aviónica ), a menudo se requiere que se cumpla la cobertura de condiciones/decisiones modificada (MC/DC) . Este criterio amplía los criterios de condiciones/decisiones con el requisito de que cada condición afecte al 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:

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

Cobertura de múltiples condiciones

Este criterio exige 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:

Cobertura de valores de parámetros

La cobertura de valores de parámetros (PVC) requiere que, en un método que recibe 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. [ 8 ] Por ejemplo, los valores comunes para una cadena son: 1) nulo , 2) vacío, 3) espacio en blanco (espacio, tabulaciones, salto de línea), 4) cadena válida, 5) cadena no válida, 6) cadena de un byte, 7) cadena de dos bytes. También puede ser apropiado usar cadenas muy largas. No probar cada valor posible de parámetro puede resultar en un error. Probar solo uno de estos podría resultar en una cobertura de código del 100%, ya que cada línea está cubierta, pero como solo se prueba una de las siete opciones, hay solo un 14,2% de PVC.

Otros criterios de cobertura

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

  • Cobertura de secuencias de código lineal y saltos (LCSAJ) , también conocida como cobertura de rutas JJ : ¿ se han ejecutado todas las rutas LCSAJ/JJ? [ 9 ] 
  • Cobertura de ruta : ¿Se han ejecutado todas las rutas posibles a través de una parte determinada del código? 
  • Cobertura de entrada/salida : ¿Se han ejecutado todas las posibles llamadas y retornos de la función? 
  • Cobertura de bucles : ¿Se ha ejecutado cada bucle posible cero veces, una vez y más de una vez? 
  • Cobertura de estados : ¿ Se ha alcanzado y explorado cada estado en una máquina de estados finitos ? 
  • Cobertura del flujo de datos : ¿Se ha alcanzado y explorado cada definición de variable y su uso? [ 10 ] 

Las aplicaciones críticas para la seguridad o que requieren alta fiabilidad suelen exigir una cobertura de prueba del 100 %. Por ejemplo, la norma ECSS -E-ST-40C exige una cobertura del 100 % de las declaraciones y decisiones para dos de los cuatro niveles de criticidad; para los demás, los valores de cobertura objetivo se negocian entre el proveedor y el cliente. [ 11 ] Sin embargo, establecer valores objetivo específicos —y, en particular, el 100 %— ha sido criticado por los profesionales por diversas razones (véase [ 12 ] ). Martin Fowler escribe: «Desconfiaría de cualquier cosa como el 100 %; daría la impresión de que alguien está escribiendo pruebas para que las cifras de cobertura sean satisfactorias, pero sin pensar en lo que está haciendo». [ 13 ]

Algunos de los criterios de cobertura mencionados anteriormente están relacionados. Por ejemplo, la cobertura de rutas implica la cobertura de decisiones, sentencias y entradas/salidas. La cobertura de decisiones implica la cobertura de sentencias, ya que cada sentencia forma parte de una bifurcación.

La cobertura completa de la ruta, del tipo descrito anteriormente, suele ser poco práctica o imposible. Cualquier módulo con una sucesión denorte{\displaystyle n}Las decisiones en él pueden tener hasta2norte{\displaystyle 2^{n}}rutas dentro de él; las construcciones de bucle pueden resultar en un número infinito de rutas. Muchas rutas también pueden ser inviables, ya que no hay ninguna entrada al programa bajo prueba que pueda hacer que se ejecute esa ruta en particular. Sin embargo, se ha demostrado que un algoritmo de propósito general para identificar rutas inviables es imposible (dicho algoritmo podría usarse para resolver el problema de la parada ). [ 14 ] La prueba de ruta base es, por ejemplo, un método para lograr una cobertura completa de ramas sin lograr una cobertura completa de rutas. [ 15 ]

Los métodos para las pruebas prácticas de cobertura de rutas intentan identificar clases de rutas de código que difieren únicamente en el número de ejecuciones de bucles, y para lograr una cobertura de "ruta base", el probador debe cubrir todas las clases de rutas. [ 16 ]

En la práctica

El software objetivo se construye con opciones o bibliotecas especiales y se ejecuta en un entorno controlado para mapear cada función ejecutada a los puntos de función en el código fuente. [ 17 ] Esto permite probar partes del software objetivo que rara vez o nunca se acceden en condiciones normales, y ayuda a garantizar que se hayan probado las condiciones más importantes (puntos de función). El resultado se analiza para ver qué áreas del código no se han probado 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 riguroso, pero manejable.

Al implementar políticas de cobertura de pruebas 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, de ser así, qué nivel de cobertura de pruebas se requiere? La progresión típica del nivel de rigor es la siguiente: Declaración, Rama/Decisión, Cobertura de Condición/Decisión Modificada (MC/DC), LCSAJ ( Secuencia de Código Lineal y Salto ).
  • ¿ La cobertura se medirá en función de pruebas que verifiquen los requisitos impuestos al sistema bajo prueba ( DO-178B )?
  • ¿El código objeto generado es directamente rastreable a las instrucciones del código fuente? Ciertas certificaciones (por ejemplo, DO-178B Nivel A) requieren cobertura a nivel de ensamblador si este no es el caso: "Entonces, se debe realizar una verificación adicional en el código objeto para establecer la corrección de dichas secuencias de código generadas" ( DO-178B ) párrafo 6.4.4.2. [ 18 ]

Los desarrolladores de software pueden consultar los resultados de la cobertura de pruebas para diseñar pruebas adicionales y conjuntos de entrada o configuración que aumenten la cobertura de las funciones vitales. Dos formas comunes de cobertura de pruebas son la cobertura de sentencias (o líneas) y la cobertura de ramas (o aristas). La cobertura de líneas 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 aristas informa qué ramas o puntos de decisión de código se ejecutaron para completar la prueba. Ambas informan una métrica de cobertura, medida como un porcentaje. El significado de esto depende de qué forma(s) de cobertura se hayan utilizado, ya que una cobertura de ramas del 67 % es más completa que una cobertura de sentencias del 67 %.

Por lo general, las herramientas de cobertura de pruebas implican cálculos y registros adicionales al programa en sí, lo que ralentiza la aplicación; por lo tanto, este análisis no suele realizarse en producción. Como es de esperar, existen clases de software que no pueden someterse a estas pruebas de cobertura, aunque se puede obtener una aproximación del mapeo de cobertura mediante análisis en lugar de pruebas directas.

También existen ciertos tipos de defectos que se ven afectados por estas herramientas. En particular, algunas condiciones de carrera u operaciones similares sensibles al tiempo real pueden quedar ocultas al ejecutarse en entornos de prueba; aunque, por otro lado, algunos de estos defectos pueden resultar más fáciles de detectar debido a la sobrecarga adicional del código de prueba.

La mayoría de los desarrolladores de software profesionales utilizan la cobertura C1 y C2. C1 se refiere a la cobertura de sentencias y C2 a la cobertura de ramas o condiciones. Con una combinación de C1 y C2, es posible cubrir la mayoría de las sentencias en una base de código. La cobertura de sentencias también abarca la cobertura de funciones, incluyendo la entrada y salida, bucles, rutas, flujo de estados, flujo de control y flujo de datos. Con estos métodos, es posible lograr una cobertura de código cercana al 100 % en la mayoría de los proyectos de software. [ 19 ]

Herramientas destacadas para la cobertura de código

Fabricantes de hardware

Software

C / C++
  • PHPUnit también necesita Xdebug para generar informes de cobertura.

Uso en la industria

La cobertura de las pruebas es un factor a considerar en la certificación de seguridad de los equipos de aviónica. Las directrices que la Administración Federal de Aviación (FAA) utiliza para certificar los equipos de aviónica están documentadas en DO-178B [ 18 ] y DO-178C [ 20 ] .

La cobertura de las pruebas también es un requisito en la parte 6 de la norma de seguridad automotriz ISO 26262 Vehículos de carretera - Seguridad funcional . [ 21 ]

Véase también

Referencias

  1. Brader, Larry; Hilliker, Howie; Wills, Alan (2 de marzo de 2013). «Capítulo 2 Pruebas unitarias: Probando el interior». Pruebas para la entrega continua con Visual Studio 2012. Microsoft. pág.  30. ISBN 978-1621140184Consultado el 16 de junio de 2016 .
  2. Williams, Laurie ; Smith, Ben; Heckman, Sarah. "Cobertura de pruebas con EclEmma" . Seminario abierto de ingeniería de software . Universidad Estatal de Carolina del Norte. Archivado del original el 14 de marzo de 2016. Recuperado el 16 de junio de 2016 .
  3. Joan C. Miller, Clifford J. Maloney (febrero de 1963). "Análisis sistemático de errores en programas informáticos digitales" . Communications of the ACM . 6 (2). Nueva York, NY, EE. UU.: ACM : 58–63 . doi : 10.1145/366246.366248 . ISSN 0001-0782 . 
  4. Paul Ammann, Jeff Offutt (2013). Introducción a las pruebas de software . Cambridge University Press.
  5. Glenford J. Myers (2004). El arte de las pruebas de software, 2.ª edición . Wiley. ISBN 0-471-46912-2.
  6. Documento de posición CAST-10 (junio de 2002). ¿Qué es una "decisión" en la aplicación de la cobertura de condición/decisión modificada (MC/DC) y la cobertura de decisión (DC)?
  7. MathWorks. Tipos de cobertura de modelos.
  8. "Pruebas unitarias con cobertura de valores de parámetros (PVC)" . 8 de mayo de 2012.
  9. MR Woodward, MA Hennell, "Sobre la relación entre dos criterios de cobertura de flujo de control: todas las rutas JJ y MCDC", Information and Software Technology 48 (2006) pp. 433-440
  10. ^ Ting Su, Ke Wu, Weikai Miao, Geguang Pu, Jifeng He, Yuting Chen y Zhendong Su. "Una encuesta sobre pruebas de flujo de datos". Computación ACM. Sobrevivir. 50, 1, artículo 5 (marzo de 2017), 35 páginas.
  11. ECSS-E-ST-40C: Ingeniería espacial - Software. Secretaría de ECSS, ESA-ESTEC. Marzo de 2009.
  12. C. Prause, J. Werner, K. Hornig, S. Bosecker, M. Kuhrmann (2017): ¿ Es razonable una cobertura de pruebas del 100 %? Lecciones aprendidas de un proyecto de software espacial . En: PROFES 2017. Springer. Último acceso: 17/11/2017
  13. Blog de Martin Fowler: TestCoverage. Último acceso: 17/11/2017
  14. Dorf, Richard C.: Computadoras, ingeniería de software y dispositivos digitales , Capítulo 12, pág. 15. CRC Press, 2006. ISBN 0-8493-7340-9, ISBN 978-0-8493-7340-4; vía Google Book Search
  15. YN Srikant; Priti Shankar (2002). The Compiler Design Handbook: Optimizations and Machine Code Generation . CRC Press. p. 249. ISBN  978-1-4200-4057-9.
  16. Marcozzi, M.; Bardin, Sébastien; Kosmatov, N.; Papadakis, Mike; Prevosto, Virgile; Correnson, Loïc (2018). «Es hora de limpiar los objetivos de tus pruebas». Actas de la 40.ª Conferencia Internacional sobre Ingeniería de Software . págs. 456–467 . doi : 10.1145/3180155.3180191 . ISBN  978-1-4503-5638-1.
  17. Garousi, Vahid; Keleş, Alper Buğra; Balaman, Yunus; Mermer, Alper; Güler, Zeynep Özdemir (mayo de 2024). «Medición de cobertura en pruebas basadas en modelos de aplicaciones web: soporte de herramientas e informe de experiencia industrial». 2024 IEEE International Conference on Software Testing, Verification and Validation Workshops (ICSTW) . págs. 37–43 . doi : 10.1109/icstw60967.2024.00019 . ISBN  979-8-3503-4479-0.
  18. 1 2 RTCA/ DO-178B , Consideraciones de software en la certificación de sistemas y equipos aerotransportados, Comisión Técnica de Radio para la Aeronáutica, 1 de diciembre de 1992
  19. Boris Beizer (2009). Técnicas de prueba de software, 2.ª edición . Dreamtech Press. ISBN 978-81-7722-260-9.
  20. RTCA/ DO-178C , Consideraciones de software en la certificación de sistemas y equipos aerotransportados, Comisión Técnica de Radio para la Aeronáutica, enero de 2012.
  21. ISO 26262-6:2011(en) Vehículos de carretera - Seguridad funcional - Parte 6: Desarrollo de productos a nivel de software . Organización Internacional de Normalización.