Una arquitectura flexible para pruebas automatizadas.
En los proyectos de software que llevamos adelante en Bitlogic, las pruebas automatizadas tienen un rol protagónico. Esto nos permite garantizar la calidad de nuestros desarrollos y reducir los tiempos de ejecución de las pruebas.
En este artículo contaremos la arquitectura de pruebas automatizadas que utilizamos, las tecnologías que elegimos y las ventajas de este tipo de soluciones.
El Stack tecnológico
Si bien existen múltiples herramientas disponibles para automatizar pruebas en aplicaciones web, hoy queremos compartir las que hemos aplicado para construir la arquitectura de una solución.
Al momento de elegir qué tecnologías utilizar nos parece oportuno utilizar herramientas de código abierto para probar conceptos nuevos y también buscar herramientas que ofrezcan la flexibilidad de enviar datos a las demás herramientas de su stack.
Selenium
Elegimos Selenium como herramienta porque maneja un navegador web de la misma forma en la que una persona usuaria lo haría, tanto de manera local como remota utilizando su servidor. Consideramos de gran valor algunas de sus principales características y funcionalidades:
- Es de código abierto
- Funciona en múltiples sistemas operativos
- Es compatible con diversos exploradores
- Se puede utilizar dentro de contenedores Docker
- Permite distribuir y ejecutar pruebas en entornos remotos paralelos usando Selenium Grid
Python
Python es el lenguaje que elegimos por su popularidad entre los programadores. Con este conocimiento disponible entre las personas del equipo se reduce la capacitación del personal en este lenguaje.
Gherkin y behave
Para que los casos de prueba fueran legibles para toda la organización, se escribieron en Gherkin (un lenguaje específico de dominio) y su ejecución se realizó con behave.
La arquitectura de la solución
Para construir la arquitectura dividimos la solución en cuatro componentes:
- Test Runner: un contenedor con los requerimientos mínimos para ejecutar los test de manera remota.
- Grid: un contenedor encargado de distribuir la ejecución de los casos de prueba según el explorador elegido.
- Node: nodos donde ejecutar las pruebas remotas.
- Finder: la herramienta de búsqueda y creación de datos de prueba.
Utilizamos las imágenes Docker oficiales de Selenium tanto para el contenedor que distribuye los tests como para los nodos que los ejecutan.
El Test Runner
Este framework se diseñó usando el patrón POM (del inglés, Page Object Model) que separa la lógica de las pruebas y la lógica para interactuar con la aplicación desde una clase por página de la aplicación. Por ejemplo, se puede crear una clase para una página de Login, otra para el inicio y así para cada vista de la aplicación. Este modelo tiene dos ventajas: evita la duplicación de código (si los métodos para interactuar con los elementos dentro de las páginas estuvieran en los tests) y reduce el mantenimiento del framework al tener una clase por cada página y dichas clases estar separadas en módulos independientes de las pruebas. Como mejora al POM clásico, se implementó una clase base “Page” que posee métodos genéricos para interactuar con páginas webs y que luego, las clases que representan cada página la heredan. A medida que el framework de pruebas evoluciona, también lo hace la clase base, ya que es necesario agregar métodos genéricos que den soporte a nuevas necesidades por parte de los tests. Contar con esta “Page” con métodos genéricos permite su reúso en proyectos futuros y ahorra tiempo al implementarla.
La herramienta de búsqueda y creación de datos
Finder se creó como un microservicio (API REST) empaquetado en una imagen de Docker. De esta manera se logró una interfaz agnóstica al lenguaje que permitió a diversos frameworks de pruebas utilizar la herramienta y ser utilizada por otras soluciones de calidad.
Finder está compuesto por cuatro módulos:
- dbHandler: módulo con el cliente de base de datos del motor Oracle para realizar consultas conocidas y comprobadas. Su salida son los primeros datos que inician el proceso de búsqueda y creación de datos de prueba.
- dataCreator: módulo con la biblioteca de “Python Request” que genera datos realizando solicitudes a las API REST del sistema legacy.
- webScrapper: módulo que interactúa con las aplicaciones del sistema legacy utilizando Selenium, inyectando de datos de pruebas y obteniendo los resultados esperados.
- apiRest: microservicio con una API REST expuesto utilizando la biblioteca Flask de Python y documentado con Swagger. Al ser un microservicio pensado para dar soporte a pruebas, sus API representan entidades del negocio específicas del proyecto. Si bien puede servir para dar soporte a pruebas en diversas aplicaciones o proyectos, no se puede reutilizar en proyectos futuros.
Conclusión
En primer lugar, la automatización de pruebas nos permite desacoplar su ejecución de las asignaciones del equipo. Al estar incorporadas en el pipeline de construcción de software, podemos ejecutarlas una y otra vez con cada cambio de código y así tener más precisión respecto a cuál de estos tuvo un impacto sobre los requerimientos. Además, permite que los especialistas de pruebas puedan concentrarse en actividades de mayor valor agregado como la identificación de nuevos escenarios, revisión de defectos con desarrolladores y un mejor entendimiento del producto.
Por otro lado, al empaquetar todas estas tecnologías en contenedores, las configuraciones son siempre las mismas haciendo que las pruebas sean más reproducibles y su ejecución en múltiples entornos, más sencilla. Todo esto ayuda a reducir los costos generales del proyecto y a mantener la calidad de los entregables.
En un próximo artículo les mostraremos los resultados cuantitativos de utilizar este tipo de arquitecturas en una reingeniería de productos.