En el desarrollo de software nos obsesionamos con las métricas. Queremos cuantificar todo, porque «lo que no se mide no se puede mejorar» (mentira en muchos contextos, aunque Drucker hiciera un mantra de esa cita de Kelvin). Para la Calidad del Software (con mayúsculas), una métrica popular es la «cobertura de código». Es una herramienta útil (luego volveré sobre esto), usarla como un KPI (o peor aún, como salvaguarda que llegue a bloquear una pull request, por ejemplo) es una mala idea.
A primera vista, parece tener sentido: si un alto porcentaje de nuestro código está cubierto por pruebas, nuestro software debe ser de alta calidad, ¿verdad? Incorrecto. La cobertura de código mide el número de lineas de código, caminos de ejecución, funciones o clases que son ejecutadas cuando se ejecutan nuestros tests. Nada más.
Si nuestros tests son de mala calidad y las validaciones que hacen son inútiles, incompletas o incluso no hay, es perfectamente posible tener una altísima cobertura de código y una calidad infame y un montón de bugs encubiertos. Lo cual es peor que no tener esa cobertura, porque nos está creando una falsa sensación de seguridad.
Por ejemplo, el siguiente test probablemente consiga una alta cobertura y enmascarando que nuestro endpoint no está probado en absoluto.
def test_helloworld(self):
response = self.client.get('/hello-world')
self.assertEqual(response.status_code, 200)
Otro problema con la cobertura de código como KPI es que es una de las métricas que más he visto convertirse en objetivo, un ejemplo claro de la Ley de Goodhart uno de los mejores ejemplos del problema contra el que nos prevenía Goldratt (“Tell me how you measure me and I’ll tell you how I will behave.”). En este caso también tiene un coste adicional (en dinero), porque el esfuerzo necesario para alcanzar el valor deseado de cobertura es mayor en proporción con los beneficios en comparación con el resto del trabajo de desarrollo.
Y es que incentiva los comportamientos equivocados. Presionado para alcanzar un cierto porcentaje de cobertura, un desarrollador tiende a escribir pruebas superficiales que simplemente ejecuten el código sin verificar realmente su comportamiento (véase el test del ejemplo). O tests que ignoren el caso de uso y verifiquen una por una cada linea del código, estando tremendamente ligados a la implementación.
Y peor aún es si la insuficiente cobertura de código es bloqueante porque no pasa los chequeos automatizados de las Github actions o el umbral definido en una Quality Gate de Sonar. ¿Qué amor le va a dar a los tests un desarrollador que ve frustrado cómo su PR no puede ser integrada en main porque al fichero que ha tocado le falta un 10% de cobertura de código?
Entonces, si la cobertura de código no es una buena métrica para la calidad del software, ¿para qué sirve?
Es decir, la cobertura de código puede ser una herramienta útil como Smell Detector de un mal testing automático. Que haya suficiente cobertura no te asegura que tus tests sean de calidad pero que haya una baja cobertura es un smell bastante fuerte.
Es una buena manera de identificar código muerto, secciones de código que realmente nunca se ejecutan y que pueden deben ser eliminadas.
Puede guiar el desarrollo de pruebas, especialmente al principio del desarrollo. También considero una buena práctica de un desarrollador que, antes de crear una pull request, compruebe la cobertura del código que ha creado o modificado. Si después de detectar una baja cobertura decide continuar adelante sin completar los tests sus razones tendrá (y se pueden evaluar más adelante).
Pues depende de qué quieras conseguir:
Si como desarrollador o líder de equipo quieres evaluar la calidad del código usa la cobertura de código como métrica periódicamente, como smell detector y, a posteriori, para localizar potenciales puntos problemáticos en el código o revaluar las razones por las que ese desarrollador ignoró una baja cobertura y siguió adelante con el commit.
Se puede ser más estricto con el TDD y hacer los tests antes que el código. De este modo es más difícil hacer tests basura y más fácil que los tests evalúen la lógica de negocio requerida por la funcionalidad en desarrollo.
Y si lo que quieres es una métrica que asegure la calidad del código, convertible en KPI o incluso barrera bloqueante para una PR defectuosa… busca en otro sitio:
Lo ideal sería encontrar una métrica que pudiera ser utilizada como KPI o threshold porque evaluara que los tests están efectivamente comprobando las reglas de negocio que rigen mi código. ¿Cuáles conoces?
2 días ago ·
Referencias:
* https://blog.securem.eu/opinions/2019/03/05/why-you-should-not-use-test-coverage-as-a-kpi/
* https://www.ben-morris.com/dont-use-test-coverage-as-a-target/
* https://marcgg.com/blog/2015/11/03/code-coverage-vanity-metric/
* https://www.reddit.com/r/programming/comments/194htrz/stop_using_code_coverage_as_a_quality_metric/
* https://neatstack.substack.com/p/stop-using-code-coverage-as-a-quality?r=8rnby&utm_campaign=post&utm_medium=web&triedRedirect=true
* https://www.danielhall.io/code-coverage-is-a-terrible-metric