El problema con la cobertura del código de ruta

por Parasoft

31 de agosto de 2011

3  min leer

¿Por qué tan pocas herramientas disponibles admiten la cobertura de rutas?

Gran cantidad de caminos

El número de posibles rutas de código normalmente aumenta exponencialmente con la complejidad ciclomática de un método. Lograr un alto porcentaje de cobertura de ruta escribiendo manualmente casos de prueba es efectivamente imposible para cualquier método que contenga más de un puñado de líneas. Incluso las herramientas de generación de pruebas automatizadas pueden tener dificultades para generar casos de prueba para una cobertura de ruta completa, especialmente cuando se trata de bucles anidados. Por ejemplo, un método con una secuencia de 10 sentencias if no anidadas ya tiene 1024 (o 210) rutas posibles. La ruta del código para un bucle que termina después de 499 iteraciones es diferente de la ruta del código del mismo bucle que termina después de 500 iteraciones. De manera similar, una operación de almacenamiento de matrices que arroja una excepción debido a una referencia nula y esa misma operación que arroja una ArrayStoreException debe tratarse como diferentes rutas de código.

Tipos de cobertura de código

La cobertura de ruta es uno de los muchos tipos de métricas de cobertura de código. Para revisar, estos son los tipos de soporte de cobertura de las herramientas de prueba de Parasoft:

Bloque básico Una secuencia de declaraciones que no se ramifican; una secuencia lineal de código sin ramificaciones de ruta de flujo de control.
Expresión booleana En C ++, una expresión booleana es simplemente una expresión que tiene un tipo 'bool'.

En C, la prueba de C ++ trata lo siguiente como expresiones booleanas:

  • Un operador relacional (<, <=, ==,>,> =,! =) Con argumentos no booleanos.
  • Cada argumento del operador booleano (||, &&,!).
  • Condicione en instrucciones if, for, while y do-while.
  • ¿Condición en? operador.
Estado Una expresión atómica booleana no constante que forma parte de la decisión MC / DC.

Una subexpresión de la decisión MC / DC se considera una condición si no contiene operadores booleanos (&&, ||,!).

Si una expresión atómica determinada aparece más de una vez en una decisión, cada ocurrencia es una condición distinta.

Decisión / Rama Decisión / Rama es la posible decisión de flujo de control que se debe tomar en el punto de derivación del código. La prueba de C ++ considera las instrucciones if-else, for, while, do-while y switch como puntos de ramificación. La prueba de C ++ no tiene en cuenta los puntos de ramificación dinámicos como los manejadores de excepciones (declaraciones throw-catch).
 Decisión MC / DC Una expresión booleana de nivel superior compuesta por condiciones y cero o más operadores booleanos. La prueba C ++ calcula MC / DC y SCC en todas las expresiones booleanas no constantes en el código fuente, excepto los inicializadores del constructor y los argumentos predeterminados de la función.
Path Una secuencia única de bloques básicos desde la entrada de la función hasta el punto de salida.

Dificultad para identificar y recorrer caminos

Las herramientas de generación de pruebas automatizadas para la cobertura de rutas primero deben determinar qué rutas de código son posibles y cuáles no, y luego deben poder generar entradas de prueba que cubran todas las rutas posibles. Ambos pasos requieren mucho tiempo y la precisión de los resultados no se puede garantizar realmente porque el análisis requerido implica problemas que se sabe que son NP-difíciles o incluso indecidibles (como el infame problema de la detención).

Desafíos de representación

A diferencia de la cobertura de declaraciones y sucursales, la cobertura de rutas es difícil de visualizar. Marcar líneas o expresiones con diferentes colores no es suficiente para transmitir este tipo de información de cobertura. Debido a esta falta de una visualización fácilmente comprensible, la cobertura de ruta sigue siendo un concepto difícil para muchos desarrolladores.

Los enfoques prácticos para lograr la cobertura de la ruta son similares para la generación de pruebas automatizada y manual. En lugar de intentar encontrar todas las rutas de código posibles, es útil centrarse en las rutas de código "interesantes". Tiene poco sentido escribir un caso de prueba que ejecute un bucle 499 veces y luego agregar otro caso de prueba que ejecute el bucle 500 veces si no sucede nada realmente diferente.

En lugar de utilizar un enfoque de arriba hacia abajo, a menudo es más útil utilizar un enfoque de abajo hacia arriba que comienza en los posibles puntos de falla y luego encuentra rutas de código que conducirían a las fallas. Los posibles alborotadores incluyen no solo posibles referencias nulas (NullPointerException), incompatibilidades de tipo (ClassCastException, ArrayStoreException), violaciones de los límites de la matriz (ArrayIndexOutOfBoundsException), sino también divisiones por cero (ArithmeticException) o posibles problemas de sincronización (IllegalMonitorStateException). La parte complicada es que estas excepciones ocurren como un efecto secundario de las instrucciones de código de bytes de bajo nivel y no se declaran en ninguna parte. Las herramientas de prueba que son capaces de realizar un análisis de flujo del código probado pueden ser muy útiles para identificar rutas de código que necesitan más pruebas.

class Listing4 {public static int add (int a, int b) {return a + b; }} la clase pública Listing4Test extiende junit.framework.TestCase {public void testAdd0 () {int result = Listing4.add (0, 0); asertEquals (0, resultado); }}

Listado 4: Un método que tiene solo una ruta de código y su correspondiente prueba JUnit

 

class Listing4 // Listado 5, en realidad {public static int add (int a, int b) {return 0; }}

Listado 5: Una implementación demasiado simplificada que aún pasaría la prueba

***

Crédito de la imagen: mar brillante

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.