Ir al contenido
wannacode

Cobertura del código

En resumen: La cobertura de sentencias pregunta si se ejecutó cada línea de código. La cobertura de ramas pregunta si cada decisión fue por los dos lados. Para la función del envío la primera necesita 2 pruebas, la segunda 3. Un 100 % de cobertura de ramas incluye el 100 % de cobertura de sentencias, pero no al revés. Y ninguna cobertura dice que se comprobó el resultado ni que el límite está en el lugar correcto.

Problema

100 % de cobertura, una tarifa equivocada

El programador ejecuta las pruebas del envío con una herramienta que cuenta qué líneas se ejecutaron. Las pruebas son dos: 0 € y 60 €. El informe dice: 100 % de las líneas.

Al día siguiente los clientes con un carrito de 30 € pagan 4,99 € de envío en lugar de 4,90 €. La línea con la tarifa sí se ejecutó. Ninguna prueba vio lo que había en ella.

La idea

La caja blanca

Hasta ahora las pruebas salían de la regla: esa es la caja negra. Las técnicas de caja blanca sacan las pruebas del código: qué líneas tiene y qué caminos puede tomar el programa.

Para esta lección no necesitas saber escribir código. Necesitas saber leer la función del envío. El lenguaje lo eliges tú, en las pestañas:

static String delivery(double total) {
if (total <= 0) {
return "rechazado";
}
double fee = 4.90;
if (total >= 50) {
fee = 0;
}
return String.format("%.2f €", fee);
}

La función tiene dos decisiones (lugares donde el programa elige un camino): «el total es 0 o menos» y «el total es 50 o más». La segunda es un «if» sin «else»: si es falsa, el programa simplemente se salta la línea que pone la tarifa a cero.

La idea

Cobertura de sentencias

La cobertura de sentencias pregunta: ¿cuántas de las líneas que hacen algo ha ejecutado al menos una prueba?

Aquí están las dos pruebas del principio, como llamadas a la función, con su salida:

System.out.println("0 € → " + delivery(0));
System.out.println("60 € → " + delivery(60));
Salida
0 € → rechazado
60 € → 0.00 €
  • 0 € pasa por la primera comprobación y devuelve «rechazado».
  • 60 € pasa por todo lo demás: la tarifa pasa a ser 4,90, luego la comprobación «desde 50» la deja en 0, luego el retorno.

Se ejecutó cada línea. La cobertura de sentencias es del 100 %, con dos pruebas.

La idea

Cobertura de ramas

La cobertura de ramas pregunta otra cosa: ¿ha ido cada decisión por los dos lados?

Aquí hay cuatro ramas: la primera comprobación verdadera y falsa, la segunda verdadera y falsa. 0 € toma la primera como verdadera. 60 € toma la primera como falsa y la segunda como verdadera. Nadie toma la segunda como falsa: ese es el camino vacío de un «if» sin «else». La cobertura es de 3 de 4, es decir, 75 %.

Una tercera prueba, con envío de pago, cierra el hueco:

System.out.println("0 € → " + delivery(0));
System.out.println("30 € → " + delivery(30));
System.out.println("60 € → " + delivery(60));
Salida
0 € → rechazado
30 € → 4.90 €
60 € → 0.00 €

Tres pruebas, 100 % de las ramas. Y la respuesta a la pregunta de la lección: el 100 % de cobertura de ramas de la función del envío necesita 3 pruebas.

Más precisamente, para curiosos

ISTQB CTFL v4.0.1 describe las dos medidas en la sección 4.3: pruebas de sentencias y pruebas de ramas. La cobertura es el número de sentencias ejecutadas (o ramas tomadas) sobre el total, en porcentaje. El plan de estudios también establece cómo se relacionan: el 100 % de cobertura de ramas incluye el 100 % de cobertura de sentencias, pero no al revés.

Hay medidas más estrictas: la cobertura de condiciones (cada condición dentro de una decisión se ha visto verdadera y falsa) y MC/DC (cada condición ha mostrado que por sí sola puede cambiar la decisión). MC/DC se exige para el software más crítico de la aviación. No están en CTFL v4.0.

La cobertura se mide con una herramienta: JaCoCo para Java, coverlet para C#, coverage.py para Python, c8 o la integrada en Node para JavaScript. Se ejecutan las pruebas, y la herramienta marca qué líneas y ramas se tomaron.

Pruébalo

¿Cuántas pruebas?

1. Una prueba con un carrito de 0 €. ¿Qué partes de la función ejecuta?
2. Las pruebas son 0 € y 60 €. ¿Cuál es la cobertura de ramas?
3. ¿Qué prueba lleva la cobertura de ramas al 100 %?

La idea

Por qué el 100 % de sentencias perdió la tarifa

Aquí está la función del principio, con la tarifa de 4,99:

static String delivery(double total) {
if (total <= 0) {
return "rechazado";
}
double fee = 4.99;
if (total >= 50) {
fee = 0;
}
return String.format("%.2f €", fee);
}

Con las dos pruebas de sentencias la salida es la misma que con la función correcta:

System.out.println("0 € → " + delivery(0));
System.out.println("60 € → " + delivery(60));
Salida
0 € → rechazado
60 € → 0.00 €

A 60 € la línea con la tarifa se ejecuta, pero justo después la tarifa pasa a ser 0. El valor equivocado nunca llega a la salida. Ejecutar no es comprobar.

La tercera prueba, la de la cobertura completa de ramas, toma el camino vacío y muestra la tarifa:

System.out.println("0 € → " + delivery(0));
System.out.println("30 € → " + delivery(30));
System.out.println("60 € → " + delivery(60));
Salida
0 € → rechazado
30 € → 4.99 €
60 € → 0.00 €

Por eso la cobertura de ramas es más fuerte. El camino vacío de un «if» es justo donde un valor de la línea de arriba llega al cliente.

La idea

Lo que la cobertura no dice

Aquí está la comprobación del límite del carrito: añadir se rechaza si es menos de 1 unidad, o si el carrito tendría más de 10.

static boolean canAdd(int inCart, int add) {
if (add < 1 || inCart + add > 10) {
return false;
}
return true;
}

Dos llamadas dan el 100 % de las ramas: (5, 0) pasa por «rechazado», (2, 3) por «aceptado».

System.out.println(canAdd(5, 0));
System.out.println(canAdd(2, 3));
Salida
false
true

Ahora cambia «> 10» por «> 11». Las mismas dos pruebas pasan, la cobertura sigue siendo del 100 %, y la unidad número 11 entra en el carrito. La cobertura mide lo que se ejecutó, no lo cerca que se estuvo del límite. La prueba (10, 1) de la lección de valores límite atrapa el error.

Y algo que ninguna cobertura puede ver: el código que falta. Si la comprobación del carrito vacío nunca se escribió, no queda ninguna línea sin cubrir. El 100 % de cobertura de un código que no hace lo que hace falta sigue siendo el 100 %. Por eso la caja blanca no sustituye a la caja negra. La cobertura dice dónde no hay pruebas, no que las pruebas sean buenas.

Ejercicio

La cobertura del límite

1. Dos condiciones, una decisión. Las preguntas son sobre la comprobación del límite de arriba.

1. ¿Cuántas pruebas necesita el 100 % de cobertura de ramas de la comprobación del límite?
2. En el código «> 10» se cambia por «> 11». ¿Dan las pruebas (5, 0) y (2, 3) un 100 % de cobertura de ramas?
3. Con las pruebas (5, 0) y (2, 3), ¿se evalúa siquiera la parte «el carrito más lo que se añade es más de 10»?

Test

Ponte a prueba

1. ¿De dónde salen las pruebas en las técnicas de caja blanca?
2. ¿Qué es verdad?
3. Las pruebas dan un 100 % de cobertura de sentencias, y una tarifa de 4,99 € en lugar de 4,90 € se escapa. ¿Por qué?
4. ¿Qué no puede decir ninguna cobertura de código?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·