Una guía para el desarrollo de unit tests en javascript con Jasmine

Este artículo está dirigido principalmente al desarrollo de unit tests con Jasmine, muchas de las recomendaciones son basadas en buenas prácticas y principios en general que ya son conocidos, otra porción se basa en recomendaciones que me han ayudado a evitar problemas a la hora de realizar TDD (Test Driven Development) desde un punto de vista personal.

Mantén cada caso de prueba simple y sencillo

Una de las razones por la cual se le llama Unit testing es debido a que fomenta la prueba de pequeñas porciones de código que poseen una función específica, esto nos permite obtener una mejor perspectiva del funcionamiento de un módulo ya que nos ayudar a comprender como las pequeñas partes del mismo deben funcionar para lograr una tarea en conjunto.

Cada caso de prueba debe ser aislado e independiente. El comportamiento de una función debe ser especificado en un solo caso y este debe ser independiente de los otros, ¿por qué?, porque el orden en el que se ejecuta cada caso no debe afectar al resto.

Los tres pilares de unit unit testing

Para que tu suite de pruebas pueda ser considerada óptima debe cumplir con tres condiciones, debe ser:

  1. Confiable
  2. Legible
  3. Escalable

Estos tres factores son el enfoque en el cual esta guía se basa.

Principios importantes

Uno de los fundamentos mas importantes para el desarrollo y práctica de TDD es el escribir código que se pueda probar o “Testear” dicho de forma burda. En general un módulo que está desarrollado bajo la metodología de TDD sigue los lineamientos ya conocidos a continuación:

  • DRY (Don’t Repeat Yourself), evita escribir código duplicado, de una u otra forma al realizar tus casos de prueba te darás cuenta que hay una gran diferencia entre reusar y repetir.
  • Buena convención de nombres, ayuda a identificar rápidamente cada función y porción de código.
  • Single responsability, algo sumamente importante es el mantener cada función u Objeto compacto y orientado a una sola tarea en específico, esto afecta de forma monumental el desarrollo y la reusabilidad de cada bloque de código.
  • Evita las dependencias, en lo posible evita la dependencia entre cada componente, encapsula y minimiza el intercambio de información entre ellos.
  • Evita el código forzado, Hard-coding no es una buena práctica en general, no solo para TDD si no para el desarrollo de módulos, permite la capacidad de personalización. Un ejemplo de código forzado:

Primero las pruebas luego el código

Una pregunta muy común, ¿Cómo puedo escribir las pruebas de un módulo si su código aún no está escrito?, respondamos a esta pregunta metafóricamente.

Compramos una cama por primera vez pero dicha cama está desarmada, ¿Qué sabemos?, sabemos que:

  • Su función es brindarnos un lugar para descansar.
  • Debe estar posicionada horizontalmente con un soporte.
  • Sobre el soporte va un colchón.

Es la primera vez que armaremos una cama, pero ya nos vamos dando cuenta que sabemos su finalidad, sabemos como podemos armarla y como debe lucir al final, mas que suficiente, es cuestión de analizar cada pieza.

De esta misma forma sucede con los unit tests, sabemos que queremos construir un módulo con una finalidad, sabemos lo que debe hacer y que para lograr su objetivo se deben cumplir un par de tareas, es solo cuestión de analizar cuales son estas tareas.

A esta forma de pensar se le conoce como Red-Green-Refactor y es una forma de desarrollo muy utilizada en el mundo de Test Driven Development, consiste básicamente en:

  1. Pensar en lo que quieres hacer y como lo quieres hacer.
  2. Escribir casos de prueba sencillos sin importar que fallen.
  3. Hacer que los tests pasen escribiendo un script minimalista que cumpla con cada función específica del test (no es importante preocuparnos por calidad de código en este paso).
  4. Refactorizar el código aplicando los Principios y patrones de diseño recomendados, haz esto de forma cíclica y mejora el código en cada vuelta.

¿Cuáles son las ventajas del desarrollo bajo TDD?

  • Al escribir las pruebas primero tu código será mas sencillo de probar.
  • Escribir las pruebas con solo los casos necesarios hace que tu code base sea lo mas pequeña posible y por tanto eficiente.
  • Es mas sencillo y confiable el agregar nuevas características y mejorar el código.
  • Identifica errores antes de que lleguen a la fase de prueba.

Estructurando tus pruebas

Anidar tus bloques de prueba proporciona mayor legibilidad a tu código.

Prueba tus casos de forma independiente

No pruebes múltiples casos en uno mismo, de esta forma puedes conseguir la fuente de los problemas de forma directa.

Evita la lógica dentro de tus pruebas

Evita utilizar condicionales y bucles dentro de tus tests, esta es una de las peores prácticas que puedes realizar ya que no hay nada peor que introducir errores dentro de las pruebas que están hechas para evitar errores.

Escribe tus pruebas por orden de complejidad

Escribe primero los casos de pruebas mas sencillos y continua escribiendo los casos mas complejos progresivamente, esto te ayudará a desarrollar los tests de forma creciente y en menos iteraciones.

No comentes tus pruebas

Tus pruebas deben ser lo suficientemente sencillas y legibles como para entenderlas sin necesidad de comentarlas, es suficiente con la descripción de la misma, descripciones cortas mantienen las pruebas sencillas y legibles.

Estas son algunas de las buenas prácticas y consejos recomendados para el desarrollo de pruebas unitarias, recuerda que como todo la mejor forma de aprender para implementar estos patrones es practicando.

¿Te gusta Reactjs y Redux? Te invito a leer este artículo: