Una de las principales ventajas de los frameworks de testing de la familia RSpec, como son Jasmine y Jest, es la capacidad de anidar los test por su contexto. Tanto el contexto de ejecución, como el documental, porque las cadenas de texto que reciben las funciones describe, e it, se concatenan cuando un test falla, de manera que podemos construir frases con sentido de negocio. Este tipo de framewoks, nos permite contar historias con los test, son una de las herramientas técnicas más expresivas para practicar storytelling.
Te habrás dado cuenta de que estoy escribiendo “test” para referirme al plural, y es que la RAE lo recoge así, porque dice que es más fácil de pronunciar. Así que ya sabes otra curiosidad, según la RAE, el plural del anglicismo test, queda igual que el singular; no son tests, ni teses.
Una pregunta frecuente en el testing es, ¿hace falta una clase o suite de test para cada clase o módulo de producción? En realidad, por cada clase o módulo de test, puede haber N clases o suites de test. Un mismo artefacto responde de manera diferente ante contextos diferentes, y esto lo podemos expresar muy bien con la anidación:
|
|
Si el primer test falla, el mensaje de error contendrá lo siguiente: “the shopping cart when it’s Black Friday offers the 3x2 disccount”.
Hay personas que gustan de utilizar un alias de la función “describe”, para llamarle “context”. Veamos otro ejemplo de agrupación por contexto:
|
|
En estos ejemplos, los contextos están dentro de la misma suite de test (describe), mientras que en otras ocasiones, los bloques describe podrían ser totalmente independientes, incluso aunque ataquen a la misma clase, módulo o función de producción ¿Cómo determinamos cuál es el contexto, para saber agrupar los test?, ¿debemos tenerlo claro a priori? Yo lo consigo a base de hacer refactoring de los test, ya que antes de escribirlos, no tengo todavía claro cuál es el contexto que comparten. Conforme voy extrayendo duplicidad de los test, muevo el código común a las funciones especiales, beforeEach y/o afterEach:
|
|
No todos los describe/context anidados están obligados a tener su propio beforeEach, a veces anidamos simplemente para documentar mejor. Lo cierto es que los métodos de preparación de contexto como beforeEach, nos dan las pistas perfectas para saber agrupar. Por ejemplo, si tengo 5 test en un mismo describe, y resulta que tengo un beforeEach, del cual algunas líneas aplican a 2 test y otras aplican a los 3 restantes, directamente puedo separar los conjuntos de test. La regla es cuidar de que todos los test que estén bajo los efectos de un beforeEach, utilicen todas las líneas que este contiene, es decir, que no falten ni sobren líneas en el beforeEach. Si encontrarnos la función beforeEach al principio, resulta molesto para la lectura, puede ponerse debajo del último test del conjunto, aunque puede resultar sorprendente para algunas personas, pues lo más habitual es verla al principio (es parte de la preparación de los escenarios).
Cuando trabajamos en el mantenimiento de baterías de test que no han seguido esta pauta de refactoring, es común que nos encontremos con suites que contienen decenas de elementos. Llegados a este punto, no es práctico el uso de la función beforeEach para inicializar, porque se van a romper muchos test. Como alternativa, podemos hacer uso de un método de inicialización al que invocamos desde los test de manera deliberada:
|
|
Así, vamos eliminando duplicidad y ruido de los test sin que se rompan. Una vez realizadas las extracciones, ya empezaría a ser más intuitivo agruparlos por contexto, como vimos en los ejemplos anteriores. Por tanto, esta idea es muy interesante para “legacy test”.
Ahora bien, si estás empezando a añadir test (green field) y usas esta técnica de invocar de manera explícita a un método de inicialización en los test (como el setup del ejemplo), corres el riesgo de no darte cuenta de agrupar los test, puesto que no ves emerger el contexto, no ves el patrón.
Mi consejo es que utilices los métodos beforeEach y afterEach para tus baterías de test nuevas, jugando a contar historias con la agrupación de contextos. Verás que así los test ayudan mucho a documentar la solución.
Hay una práctica que me he encontrado en varios proyectos, que es llamar sut a la variable que representa la instancia de la clase que queremos probar (o al módulo). SUT viene de System Under Test, aunque también lo he visto como Subject Under Test. Es una idea que puede ser interesante para legacy test, cuando los test son enormes y tienen tantas líneas que no es fácil distinguir qué se está queriendo probar entre toda la maraña.
Para código green field, mi recomendación es llamar a las instancias por su nombre de negocio, porque así nos hacemos una mejor idea de si la API es intuitiva:
|
|
Al utilizar el nombre de la clase (o módulo) seguida del nombre del método (o función), estamos construyendo frases con sentido de negocio, con mayor expresividad. Es más claro así, que como “sut.checkout”. Otro beneficio cuando rechazamos el uso de “sut”, es que de nuevo obtenemos más pistas sobre cómo agrupar nuestros test. Si estamos probando “shoppingCart”, va a cantar mucho que los test de “billing” estén en el mismo saco, mientras que si a todo le llamamos “sut”, quizá no sea tan evidente.
Las tácticas que usamos cuando el código es legado, a menudo distan de las que están a nuestra disposición cuando tenemos la suerte de trabajar en un green field. Todo esto y mucho más sobre cómo escribir test más fáciles de entender y mantener, lo tienes en mi libro, Diseño Ágil con TDD. Si te he gustado esta entrada, te gustará el libro.
¿Quieres más? te invitamos a suscribirte a nuestro boletín para avisarte cada vez que recopilemos contenido de calidad que compartir.
Si disfrutas leyendo nuestro blog, ¿imaginas lo divertido que sería trabajar con nosotros? ¿te gustaría?
Pero espera 🖐 que tenemos un conflicto interno. A nosotros las newsletter nos parecen 💩👎👹 Por eso hemos creado la LEAN LISTA, la primera lista zen, disfrutona y que suena a rock y reggaeton del sector de la programación. Todos hemos recibido newsletters por encima de nuestras posibilidades 😅 por eso este es el compromiso de la Lean Lista