La cobertura de código no significa nada

No deja de sorprenderme cuanta gente le da una importancia excesiva al valor de la cobertura. Entiéndaseme bien, al valor absoluto de la cobertura. A la cifra en si.

¿Qué significa tener una cobertura del 75%? ¿Nos dice algo este 75%? Pues la verdad es que algo dice, pero muy poco. El motivo es sencillo, una simple cifra nos da muy poca información sobre nuestro testeo unitario. Esa cifra no nos dice cómo están distribuidos nuestros test unitarios, tampoco nos dice mucho sobre la calidad de los mismos, ni sobre su mantenibilidad, ni menos aun sobre el tiempo que tardan en pasar…

¿Qué situación os parece mejor? Una batería de test unitarios con una cobertura del 75% en todos los componentes o una batería de test con una cobertura del 95% en aquellos componentes de la arquitectura que más cambian y una cobertura media del 60% en el resto. Si yo pudiese elegir en que aplicación trabajar, elegiría esta segunda. Seguro que los test unitarios me van a resultar más útiles.

Miremos ahora otro aspecto importante del los test unitarios. Supongamos una aplicación con una cobertura del 90% por cierto, pero que a cambio de obtener esta cobertura hemos tenido que sacrificar la velocidad de ejecución de los test. ¿Es esta una buena situación? ¿Es conveniente sacrificar otros aspectos como velocidad, mantenibilidad, tiempo consumido en su escritura excesivo, etc… para conseguir mayor cobertura? ¿Es aumentar la cobertura a cualquier precio una buena decisión?. Evidentemente no. No debemos nunca olvidar que la cobertura no sirve si olvidamos qué hace a un test unitario un buen test.

La cobertura es importante, sumamente importante,  pero solo puesta en contexto. Siempre que miramos a las métricas debemos hacerlo desde un enfoque multidimensional. Mi cobertura es el X% es una afirmación que no nos dice nada, pero que oímos habitualmente. Cuando miramos al porcentaje de cobertura de nuestro código debemos hacerlo desde un enfoque crítico siempre acompañado de una mirada a otros aspectos de nuestro testeo unitario, entre otros:

  • Son los test mantenibles: Aspecto fundamental, si tu test no son fáciles de mantener, da igual lo que hagas, su cobertura se irá reduciendo con el tiempo.
  • Tienen más test la partes más importantes: Es una simple cuestión de economía, si tus recursos son limitados, y siempre lo son, debemos enfocar nuestros esfuerzos en aquellas partes en las que el testeo nos va a dar mejores resultados. Prestar más atenciones a aquellas partes de nuestra aplicación más propensas a cambios, luego aquellas de las que dependen otras, luego aquellos que son compartidos por varios proyectos, etc…
  • Cuál es la relación coste beneficio de nuestro testeo unitario: debemos valorar situaciones como ¿realmente interesa complicar el proyecto con una librería de mockeado solo para ganar cobertura marginalmente?, ¿añadir un poco más de cobertura será a costa de enlentecer significativamente nuestros test?, ¿por un puntito más de cobertura vamos a añadir nuevas dependencias a nuestros test?, etc..

Cuando la cobertura muestra toda su potencia, como en general cualquier métrica, es cuando se estudia cómo está evolucionando. La evolución de la cobertura es lo realmente importante. Ese es el aspecto clave. El problema es que casi cualquier framework de testeo unitario, por si mismo o combinado con alguna herramienta especifica, es capaz de darte informarte de cual es tu cobertura en un momento determinado, pero recoger la evolución de la cobertura es algo mucho más complejo. Para empezar necesitas como mínimo un proceso de construcción automatizado, un repositorio donde recoger la evolución de la cobertura, y un mecanismo para representarla.

Los afortunados que usamos Visual Studio y Team Foundation Server contamos con todo lo necesario para tirar del hilo y mirar nuestro testeo unitario de manera poliédrica.

Podemos ver la cobertura por modulo, namespace o clase de nuestra aplicación:

Podemos ver cómo evoluciona la cobertura en relación a los cambios en el código y el número de bugs:

Example Build Quality Indicators report

Ver si nuestras builds tienen cobertura suficiente y sobre todo si están pasando de situaciones de cobertura suficiente a menos cobertura:

Healthy and Unhealthy version of Build Success

Example Build Summary report

En conclusión ojo con pensar que un porcentaje de cobertura determinado es indicador suficiente.

Un saludo.

8 comentarios en “La cobertura de código no significa nada”

  1. Me hace gracia leer esta entrada, porque parece una rabieta por la falta de entendimiento con el responsable de proyecto.
    Lo más importante de una métrica es entenderla. Y en este mundillo hay mucha gente que solo ve un número y le gusta que sea lo más alto posible. Pero lo más triste es que acabo de salir de un proyecto en el que la única métrica que conocía el responsable de proyecto es las horas que pasas sentado delante del ordenador. Vamos que si le hablo de test unitarios piensa que le hablo de naves espaciales.
    Sabéis como se puede conseguir métricas como número de bug que genera un desarrollador. Tiempo en resolver esos bug. Mantenivilidad del código que se genera, … Porque esas son las importantes y las que te llevan un proyecto a la mierda.

  2. @Andréchi:
    No es una rabieta por nada. Gracias a Dios hace mucho que no tengo rabietas. El principal motivo es que soy mi jefe, solo me debo a mi equipo y a mis clientes. No responde ante ningún ‘responsable de proyecto’.

    Este post tiene su origen en diversas conversaciones con gente que está empezando en el testeo unitario y que hace de la cobertura una especie de bala de plata.

    Aunque sé como obtener métricas como ‘número de bugs por desarrollador’ también se que esa métricas son de nula utiliada, porque miden al individuo y no al proceso. Medir al individuo no sirve de nada, el individuo siempre es más listo que las métricas y las va a sesgar a su favor de manera natural. Las métricas solo sirven y solo deben ser usadas para medir tu proceso.

    Sobre la mantenibilida del código… ya molaría si se puediese medir… pero es imposible de medir. No hay una forma única y objetiva de conseguir código mantenible. El código mantenible es el resultado de muchos aspectos diferentes, todos ellos sumamente dificiles de medir.

    ¡Un saludo!

  3. Una vez más -> u’re right !!!

    Los aspectos que más debemos tener en cuenta son aquellos que indican que algo “ha cambiado” y que no ha sido controlado. Por ejemplo, si entre dos Nightly Builds, mi CC baja de un 85% a un 50%, pues algo hemos hecho -> seguramente agregar el código fuente de un componente de 3ros sin pruebas o ve tu a saber qué puede ser.

    En este aspecto, yo me la he pasado muy bien algunas veces, donde algunos equipos de desarrollo que “tenian que cumplir un 90% de CC por contrato”, pues se dedicaban a tirar Unit Tests sin sentido, solo para subir el CC. Ellos eran concientes que sus pruebas unitarias no servían ni tampoco permitian definir el contrato de trabajo cumplido por su código, pero su jefe estaba muy jappy jappy con su CC del 90%. Eso sí, los componentes cascaban como una escopeta de feria … y si @Andreichi, en mi caso es una experiencia de un proyecto no tan antiguo.

    Lo bueno, cuando la gente comienza a cambiar la forma de trabajo y empieza a aprovechar las virtudes de una herramienta como VS+TFS; pues la calidad (cuya métrica muchas veces es imposible de medir) sube exponencialmente.

    Salu2 y perdón por el comentario/post, se me ha extendido un poco XD

  4. Supongo que es de naturaleza humana reducirlo todo a una cifra.
    Así las cámaras digitales se miden en Megapíxels, dejando de lado su óptica, o las unidades de CDROM las medíamos por si eran 30x, 42x ó 50x, dejando de lado que esto eran picos y no velocidades sostenidas…

    Y con los tests unitarios ocurre lo mismo: lo reducimos todo a un número, el % de cobertura, aún cuando ese número por si sólo no diga nada como bien apuntas…

    Saludos!

  5. @Bruno: gracias por tus aportes. Como siempre acertados.

    @Eduard: ¡me encanta el simil! No lo había mirado desde esa óptica pero tienes toda la razón. ¡Es la naturaleza humada!.

    Un saludo.

  6. Hola, pues estoy de acuerdo.

    Coverage es solo una cifra que por si sola no dice nada.
    Imagina un código con cobertura 100% con test ¿está libre de fallos?
    Pues no, porque es imposible cubrir fallos por falta de código. Comprobar consistencia de datos y demás.

    O supongamos una librería integrada, que solo es cubierta con un 30% ¿es malo?
    Pues a lo mejor tampoco en ese contexto, porque los casos de uso funcionales pueden tener una cobertura muy alta, y la parte que no se testea. Y los test de componentes integrados valen más que los test unitarios.

    Pero no deja de ser una cifra, que como dicen por ahí arriba, cuanto más alta, más mola

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *