Me pregunto si medir la cobertura de código condicional mediante las herramientas actuales para Java no es obsoleto desde que surgió Java 8. Con Java 8 Optional
y a Stream
menudo podemos evitar ramas / bucles de código, lo que facilita obtener una cobertura condicional muy alta sin probar todas las rutas de ejecución posibles. Comparemos el antiguo código Java con el código Java 8:
Antes de Java 8:
public String getName(User user) {
if (user != null) {
if (user.getName() != null) {
return user.getName();
}
}
return "unknown";
}
Hay 3 posibles rutas de ejecución en el método anterior. Para obtener el 100% de la cobertura condicional, necesitamos crear 3 pruebas unitarias.
Java 8:
public String getName(User user) {
return Optional.ofNullable(user)
.map(User::getName)
.orElse("unknown");
}
En este caso, las ramas están ocultas y solo necesitamos 1 prueba para obtener una cobertura del 100% y no importa en qué caso probaremos. Aunque todavía hay las mismas 3 ramas lógicas que deberían cubrirse, creo. Creo que hace que las estadísticas de cobertura condicional sean completamente desconfiadas en estos días.
¿Tiene sentido medir la cobertura condicional para el código Java 8? ¿Hay alguna otra herramienta para detectar código no eliminado?
fuente
getName
? Parece ser que siuser
es nulo, debería devolver "desconocido". Siuser
no es nulo yuser.getName()
es nulo, debería devolver "desconocido". Siuser
no es nulo yuser.getName()
no lo es, debería devolverlo. Por lo tanto, haría una prueba unitaria de esos tres casos porque de eso se trata el contratogetName
. Parece que lo estás haciendo al revés. No desea ver las ramas y escribir las pruebas de acuerdo con ellas, desea escribir sus pruebas de acuerdo con su contrato y asegurarse de que el contrato se cumpla. Ahí es cuando tienes una buena cobertura.Respuestas:
No estoy al tanto de ninguno. Intenté ejecutar el código que tienes a través de JaCoCo (también conocido como EclEmma) solo para estar seguro, pero muestra 0 ramas en la
Optional
versión. No conozco ningún método para configurarlo para decir lo contrario. Si lo configuró para incluir también archivos JDK, teóricamente mostraría ramasOptional
, pero creo que sería una tontería comenzar a verificar el código JDK. Solo tienes que asumir que es correcto.Sin embargo, creo que el problema central es darse cuenta de que las ramas adicionales que tenía antes de Java 8 eran, en cierto sentido, ramas creadas artificialmente. Que ya no existan en Java 8 solo significa que ahora tiene la herramienta adecuada para el trabajo (en este caso
Optional
). En el código anterior a Java 8, tenía que escribir pruebas unitarias adicionales para poder confiar en que cada rama de código se comporta de manera aceptable, y esto se vuelve un poco más importante en secciones de código que no son triviales comoUser
/getName
ejemplo.En el código Java 8, en cambio, confía en el JDK de que el código funciona correctamente. Tal como está, debe tratar esa
Optional
línea tal como lo tratan las herramientas de cobertura de código: 3 líneas con 0 ramas. Que haya otras líneas y ramas en el código a continuación es algo a lo que no ha prestado atención antes, pero ha existido cada vez que ha usado algo como unArrayList
oHashMap
.fuente
if
ynull
son todavía partes de la lengua ;-) Todavía es posible escribir código en forma de edad y pasarnull
usuario o usuario connull
nombre. Sus pruebas solo deben probar que se cumple el contrato, independientemente de cómo se implemente el método. El punto es que no hay una herramienta que le diga si probó completamente el contrato.Optional
(y los métodos relacionados), ya no tienes que probarlos. No de la misma manera que probaste unif-else
: todoif
era un campo minado potencial.Optional
y modismos funcionales similares ya están codificados y se garantiza que no te harán tropezar, por lo que esencialmente hay una "rama" que desapareció.Optional
. Como dijo, lógicamente aún deberíamos probar quegetName()
maneja varias entradas posibles en la forma en que pretendemos, independientemente de su implementación. Es más difícil determinar esto sin herramientas de cobertura de código que ayuden de la forma en que sería anterior a JDK8.if-else
porque cada uno de esos constructos es completamente ad-hoc. Por el contrario,Optional
,orElse
,map
, etc, están todos ya probado. Las ramas, en efecto, "desaparecen" cuando usas modismos más poderosos.