Después de 3 semanas, doy por concluida (por el momento), la serie sobre cómo no escribir tests unitarios. Por el camino he contado algunas de las cosas que más daño me han hecho al escribir tests unitarios, y aunque me quedan más, creo que no son tan aplicables genéricamente como las que hemos visto hasta ahora.
He tratado en cada post de forma independiente una mala práctica, pero realmente algunos casos eran distintas manifestaciones de un problema más general. Quiero aprovechar este resumen de la serie para mostrar esos problemas generales, que a veces se manifestarán con los antipatrones descritos en la serie y a veces de forma diferente.
Los tests deben comprobar que algo funciona
Puede parecer que es obvio que los tests están escritos para verificar el comportamiento de algo, pero muchas veces acabamos escribiendo y manteniendo muchos tests que no nos aseguran que la aplicación funciona como debe.
Es lo que ocurre cuando replicamos la lógica a testear en el propio test o abusamos de los tests de interacción.
No hay nada peor que tener una parte de código bien cubierta con tests, incluso con el 100% de cobertura, y no poder refactorizar el código porque no nos fiamos de que los tests vayan a detectar los errores que introduzcamos.
Los tests tienen que ser independientes de lo que no están testeando
Dejando de lado lo que se tome como unidad al escribir un test unitario, un test debe estar enfocado a verificar un aspecto concreto del código. Hay que evitar que un test dependa de otras áreas del código que no son importantes para él.
Son casos como los que veíamos con la dependencia de constructores y APIs y que podíamos evitar usando patrones como ObjectMother y Builder.
Si no cumplimos esto, cada vez que refactoricemos una parte de código será necesario cambiar muchos tests que no tienen nada que ver con los cambios que hemos hecho, haciéndonos trabajar de forma innecesaria y arriesgándonos a introducir nuevos errores.
Los tests deben ser legibles y fáciles de entender
Siempre es importante que el código que escribimos sea legible, claro y fácil de entender, pero en el caso de los tests esto es crítico.
Un test debe dar confianza sobre el código testeado. Debemos estar seguros de que si se pasa un test, el código funciona, y si se falla, el código no funciona. Cuando la estructura de las propias clases de test es compleja o el código no es claro, en el momento en que se produce un fallo tenemos que empezar a analizar si el test realmente está bien escrito, haciendo que nuestra confianza en el test disminuya y, por tanto, su utilidad también.
Para evitar esto, hay que tratar de evitar las jerarquías de clases de test y diseñar el código de forma que sea fácilmente testeable con tests de estado que son más sencillos de inspeccionar y comprender de un vistazo. También el uso de ObjectMother
s y Builder
s ayuda a quitar ruido de los tests y nos permite ver más fácilmente qué queremos testear y cómo lo estamos testeando.
Los tests no son gratis
Los test no dejan de ser código y como tal han de ser escritos y mantenidos a lo largo del tiempo. A veces nos dejamos llevar «ciegamente» por las buenas prácticas y escribimos tests para todo, pero aplicar el sentido común a la hora de escribir tests también es importante.
Soy el primero que cree que los tests son una de las herramientas más útiles que existen para crear aplicaciones de calidad, pero escribir tests indiscriminadamente para lograr la quimera de un 100% de cobertura de código no siempre es una buena idea.
Hay tests extremadamente valiosos que merece al pena escribir, mantener y lo que haga falta, porque son los que realmente nos ayudan a estar seguros de que las cosas funcionan como deben, pero hay otros cuya utilidad es mucho más dudosa.
No pasa nada por dejar áreas de código sin cubrir con tests. Hay partes de una aplicación que, por muchos tests que escribamos, van a seguir necesitando pruebas manuales. En ese caso hay que analizar si merece la pena intentar escribir pruebas automatizadas que, probablemente, sean frágiles y no nos sirvan para tener la certeza de que el código funciona. En estos casos puede ser más útil escribir tests de aprobación que test completamente automatizados.
Llevo tiempo siguiendo tu blog, (que descubrí en planetacodigo.com) y esta serie sobre los Tests ha sido muy interesante.
Gracias por compartirlo :-)
Gracias por el comentario, Daniel. Me alegro de que te haya resultado interesante la serie.
Muchas gracias por esta colección de artículos sobre test unitarios me ha parecido muy interesante.