X
BLOG

Métricas de cobertura de prueba unitaria

Métricas de cobertura de prueba unitaria Tiempo de leer: 3 minutos

Independiente del granularidad de cobertura, hay varios criterios de cobertura diferentes que tienen en cuenta diferentes aspectos de la cobertura.

El alcance de los diversos criterios de cobertura se ilustrará utilizando el método Java que se muestra en el Listado 2. El método de muestra no realiza ninguna operación práctica, pero es bastante simple y muy útil para ilustrar todos los criterios de cobertura discutidos en este artículo. Por razones de simplicidad, el método probado solo tiene un único parámetro de entrada. Sin embargo, dado que un método con dos parámetros también se puede ver como un método con un parámetro que resulta ser un par o tupla, los conceptos discutidos en este artículo se aplican igualmente a los métodos con múltiples parámetros.

Cobertura de estados de cuenta

El criterio de cobertura más básico es la cobertura de la declaración (también denominada a veces "cobertura en bloque"). La cobertura completa de la declaración se logra cuando cada declaración de un método probado es ejecutada por al menos un caso de prueba. Para el método de muestra del Listado 2, dos casos de prueba, utilizando los valores de entrada 0 y 1, son suficientes para lograr una cobertura completa de la declaración. En el Listado 3 se muestra una prueba JUnit correspondiente. El cuerpo de la primera instrucción if se ejecutará para ambas entradas.

La cobertura de la declaración no tiene en cuenta lo que sucedería si la condición de la primera declaración if se evaluara como falsa, en cuyo caso el cuerpo de la primera declaración if no se ejecutaría. En la práctica, es igualmente importante considerar lo que sucede cuando no se ejecuta una determinada parte del código. La prueba de tales situaciones debe ir más allá de la mera verificación de que se ejecutó cada declaración.

Listado de clase pública2 {método público estático int [] (entrada de byte) {condición booleana1 = (entrada & 1) == 0; condición booleana2 = (entrada & 2) == 0; int salida = -1; if (condición2) {salida ++; } if (condition1) {return null; } else {return new int [salida]; }}}

Listado 2: Ejemplo de método Java para demostrar diferentes criterios de cobertura

La clase pública Listing3 extiende junit.framework.TestCase {public void testMethod0 () {int [] resultado = Listing2.method ((byte) 0); asertNull (resultado); } public void testMethod1 () {int [] result = Listing2.method ((byte) 1); asertEquals (0, result.length); }}

Listado 3: Ejemplo de caso de prueba de JUnit que proporciona una cobertura de declaración del 100% para el Listado 2

Cobertura de sucursales

El criterio de cobertura que tiene en cuenta estas situaciones se denomina cobertura de sucursales (también conocido como cobertura de afecciones o cobertura de decisiones). La cobertura de rama completa requiere que todos los resultados posibles de una expresión condicional sean ejecutados por un caso de prueba. Para el método de muestra, esto significa que debe haber una entrada de prueba en la que condition2 (en la primera instrucción if) se evalúe como falsa y, por lo tanto, se omita el cuerpo de la primera instrucción if. Para lograr una cobertura de sucursales del 100% para el método de muestra, puede agregar un tercer caso de prueba que use un valor de entrada de 2. El caso de prueba que usa 0 como entrada sería redundante en este escenario. Si las entradas de prueba se eligen con cuidado, es posible que pueda lograr una cobertura de rama completa con la misma cantidad de entradas. Sin embargo, esta no es una regla general y es posible que necesite más casos de prueba para lograr la cobertura de sucursales de los que necesita para lograr la cobertura de declaraciones.

Cobertura de ruta

¿La cobertura del 100% de la sucursal garantizará que un fragmento de código esté libre de errores? Aunque presenta una mejora significativa con respecto a la mera cobertura de declaraciones, la cobertura completa de sucursales aún no ofrece garantía de que un fragmento de código siempre se comporte correctamente.

El método de muestra del Listado 2 puede generar una NegativeArraySizeException en determinadas circunstancias. Este problema ocurre para todas las entradas en las que se omite el cuerpo de la primera instrucción if porque condition2 se evalúa como falsa y, al mismo tiempo, condition1 también se evalúa como falsa. En estos casos, el código intentará asignar una matriz de tamaño -1. La cobertura de la rama cubre ambas alternativas de la segunda instrucción if, pero no garantiza que la rama else de la instrucción esté cubierta en combinación con el cuerpo de la primera instrucción if que se omite.

Para proporcionar cobertura para tales situaciones, necesitamos buscar combinaciones de ramas, también conocidas como rutas de código. Este criterio de cobertura se denomina cobertura de ruta. La cobertura de la ruta requiere no solo que cada bifurcación posible se ejecute al menos una vez, sino también que cada combinación posible de bifurcaciones se ejecute al menos una vez.


Figura 1: Diagrama de actividad UML con posibles rutas de código a través del método de muestra

La Figura 1 muestra el flujo de control del método de muestra del Listado 2 como diagramas de actividad UML. En cada diagrama, una ruta de código diferente se resalta en rojo negrita. El método de muestra tiene un total de cuatro rutas de código diferentes. Para lograr una cobertura de ruta del 100%, necesita un mínimo de cuatro casos de prueba diferentes (por ejemplo, utilizando los valores de entrada 0, 1, 2 y 3).

Escrito por

Parasoft

Las herramientas de prueba de software automatizadas líderes en la industria de Parasoft respaldan todo el proceso de desarrollo de software, desde que el desarrollador escribe la primera línea de código hasta las pruebas unitarias y funcionales, hasta las pruebas de rendimiento y seguridad, aprovechando los entornos de prueba simulados en el camino.

Reciba las últimas noticias y recursos sobre pruebas de software en su bandeja de entrada.

Prueba Parasoft