Automatizando con JavaScript

Por Cristian Barrientos.

Cristian Barrientos

Gran parte del tiempo que pasamos escribiendo código para nuestras aplicaciones web tenemos  la constante preocupación de no afectar algo que ya esté funcionando correctamente y que el código que estamos escribiendo sí solucione el problema principal que motivó su construcción, lo que podemos definir como los mínimos criterios cuando esté siendo usado.


Una de las formas que en las que podemos lograr (o por lo menos intentar) disminuir esa preocupación es por medio de la construcción de pruebas del código, que de una forma predictiva y explícita verifiquen que el funcionamiento del código cumple con las especificaciones óptimas de funcionamiento.

Dentro del entorno de desarrollo web, se han creado diferentes formas de hacer pruebas y de definir qué exactamente debería probarse, dentro de lo cual, existen diferentes opiniones y extensas discusiones, pero desde un punto de vista pragmático, la manera más simple de acercarse al mundo de la pruebas es por medio de lo que Kent C. Dodds planteó como el trofeo de las pruebas en JavaScript.


Pruebas unitarias

Las pruebas vienen en diferentes formas, la más primitiva es una prueba unitaria, que busca probar una unidad de código y asegurar que las afirmaciones propuestas se cumplen, es decir, una prueba unitaria no es más que un bloque de código donde se proponen afirmaciones que luego son verificadas contra el código de nuestra aplicación.


Dentro de las preguntas más frecuentes respecto a las pruebas unitarias se encuentran:

  • ¿Qué es una unidad de código?

  • ¿Qué tamaño tiene?


Y la respuesta es que nadie lo sabe, y tampoco está definido el tamaño, por lo que no es importante determinarlo, por el contrario podemos ver una unidad como una pieza de código que puede probarse de manera aislada del resto de nuestra aplicación.

Pruebas de integración

Las pruebas de integración buscan verificar que múltiples unidades de la aplicación funcionan de manera correcta cuando se integran, es decir, que si tenemos pruebas unitarias aisladas para dos componentes de nuestra aplicación, pero en el contexto del sistema estos dos componentes realmente funcionan de manera conjunta, la prueba de integración es la manera de verificar y asegurar el correcto funcionamiento de esta integración.

Pruebas Extremo a Extremo (End to End, E2E, Cypress)

Típicamente, estas pruebas corren contra todo el sistema, es decir la aplicación Web (Frontend) y el servidor (Backend), y estas pruebas interactúan con la aplicación de la forma que un usuario lo haría, simulando desde lo más cerca posible el uso real de la aplicación.

Cypress es una de las herramientas disponibles para construir este tipo de pruebas. Cypress ejecuta la aplicación dentro de un navegador y permite, por medio de una API, especificar el comportamiento de las pruebas que va a ser simulado dentro de la aplicación.

Herramientas de análisis estático de código

Existen herramientas que permiten disminuir al máximo los posibles errores de codificación que pueden ser evitados antes de llegar a producción, es decir, capturar errores simples como: errores de escritura, errores de tipos, mal uso evidente de API de desarrollo.


Las principales herramientas que pueden ser usadas dentro de esta categoría que tienen mejor retorno de la inversión de esfuerzo son:

ESLint

ESLint es un analizador de código estático que busca, por medio de reglas, validar que el código tenga los estándares definidos. La mayoría de reglas están definidas por la comunidad y existe, recomendado directamente por ESLint, (aunque también por la comunidad), el paquete de reglas desarrolladas por AirBnB.

Prettier

Prettier es un formateador de código que busca que todo el repositorio de código fuente de las aplicaciones mantenga un estándar de estilo, y en conjunto con ESLint, de reglas. 

Su forma de funcionamiento es, por defecto, a través de una utilidad de consola de comandos, pero el método preferido por la comunidad es por medio de una integración con los editores de código, los cuales  permiten, mediante la acción de guardar un archivo, formatear todo el código, automáticamente.

Uso de tipos: (Flow - TypeScript)

Javascript es un lenguaje dinámicamente tipado, lo que significa que no es necesario poner los tipos de variables ya que internamente el código es interpretado en vez de compilado. En este proceso, el motor de interpretación de código javascript solo evalúa el código esperando que el desarrollador utilice los tipos válidos para ejecución del mismo.


Usar un “SuperSet” de código javascript, tal como TypeScript o Flow, permite que el desarrollador codifique de una forma altamente tipada, especificando concretamente qué tipos va a usar dentro del código, es decir, poniendo reglas de entrada y salida en todos los procedimientos de ejecución de código, lo que incrementa exponencialmente la posibilidad de capturar errores en el código por problemas en los tipos de datos antes  que el código sea desplegado a ambientes de producción.

También se puede argumentar el caso de que un desarrollador puede ser más productivo una vez ha aprendido a manejar alguna de estas herramientas, pero esto no viene sin el precio de la curva de aprendizaje de las nuevas formas de codificar.

Entorno de ejecución: Jest

Las pruebas unitarias y de integración necesitan un entorno en el cual ser ejecutadas, es decir, una herramienta que pueda validar cada una de las pruebas y entregar el resultado.

Jest es un framework de pruebas de Javascript que está enfocado en la simplicidad de uso y su pilar principal es asegurar la exactitud de cualquier repositorio código fuente escrito en Javascript.

Dentro de sus características principales se pueden destacar:

  • Cero configuración: Jest busca funcionar de manera simple y rápida, por eso no es necesario hacer ninguna configuración en la mayoría de proyectos Javascript.

  • Snapshots: Las pruebas crean objetos que guardan estados con los cuales se puede rastrear si una prueba debe ser ejecutada de nuevo y cuando sea ejecutada, que se verifique rápidamente contra una muestra del último objeto guardado.

  • Aislado: Las pruebas se paralelizan ejecutándose en sus propios procesos para maximizar rendimiento

  • Estupenda API: Jest tiene todo el conjunto de herramientas en un solo lugar:  Bien documentado, bien mantenido.

Conclusión

Crear una cultura donde las pruebas no solamente sean bienvenidas sino altamente deseadas es una tarea de todos nosotros como desarrolladores, que aparte de hacernos la vida más simple en cuanto a entregar código mucho más confiable, también es gesto de amabilidad con la siguiente generación que tome el código que nosotros dejamos, de esa forma, pueden gastar menos tiempo evitando dañar partes del sistema y más tiempo en producir valor por medio del código.

En Javascript tenemos múltiples metodologías para una mejor implementación de esta cultura, desde el nivel más simple (menor esfuerzo) al más complejo (mayor esfuerzo) tenemos: 

  • Herramientas de análisis estático de código: que nos ayudan a detectar errores de desarrollo desde el momento en que escribimos el código

  • Pruebas Unitarias: En las que buscamos probar elementos aislados de nuestro sistema.

  • Pruebas de Integración: En las que buscamos probar un conjunto de unidades aisladas contra un comportamiento deseado.

  • Pruebas de extremo a extremo: En las que por medio de la programación de un robot simulamos la interacción de un usuario real del sistema para probar el sistema de punta a punta en cuanto interacción de todos sus componentes.

Con esta combinación de niveles de pruebas buscamos mantener una consistencia y confiabilidad alta en el sistema, con la cual avanzar dentro del marco de entregar valor por medio de código y no correr bajo la ansiedad de romper antiguas piezas de funcionamiento en el sistema, sino, por el contrario, en trabajar de manera eficaz y eficiente en entregar ese valor que como desarrolladores tenemos la posibilidad de crear.

Comparte este post

   #IASSOFTWARE