Las pruebas automáticas de software en mi equipo

Encontrar defectos en el software que desarrollamos es de gran importancia para asegurar la correcta ejecución de nuestra aplicación así como la buena experiencia e interacción del usuario.

En el contexto de las aplicaciones de software médicas mantener la calidad de los productos que se desarrollan es aún más relevante. El riesgo que puede ocasionar al paciente un defecto en la aplicación puede ser de suma gravedad y por lo tanto sujeto a investigación por parte de los organismos regulatorios.

Independientemente del área donde la aplicación es utilizada considero que un desarrollo dirigido por pruebas (test driven development o TDD) es una aproximación correcta para el área de ingeniería del software, donde se busca mantener un producto en funcionamiento a lo largo de varios años.

Aunque las pruebas pueden ser llevadas a cabo por una persona (ingeniero de calidad o tester) la escala y velocidad de desarrollo actuales no puede ser implementada si se tiene demasiada interacción humana de por medio ya que cada cambio introducido en las aplicaciones require de una retroalimentación para asegurar que no se han añadido fallos. Es preferible entonces implementar una solución automatizada y confiable que sea capaz de escalar de acuerdo al tamaño y complejidad de las aplicaciones.

Con esto en mente en mi equipo hemos puesto en funcionamiento una suite de pruebas (o tests) para cada uno de nuestros productos. Dicha suite es ejecutada previo a la introducción de cambios en el código y, en algunos casos, como acción posterior o asíncrona en ciertos entornos.

Las “historias” y los defectos en nuestro ciclo de desarrollo

Nuestro ciclo de desarrollo sigue la práctica de la metodología Agile y está organizado en Sprints que duran dos semanas. Dichos Sprints son alimentados por medio de tickets donde se escriben las historias que definen las funcionalidades a implementar, los defectos (bugs) que debemos arreglar así como otro tipo de actividades realizadas por el equipo.

Las historias cuentan con una lista de criterios que se deben de cumplir para considerarla como completa (acceptance criteria). Dicha lista es definida por el equipo de producto y enriquecida o disminuida junto con el equipo de ingeniería.

Los defectos cuentan con una sección donde se especifica el comportamiento deseado del producto además de otra información para ayudar al ingeniero a resolverlo.

El enfoque

En nuestro equipo escribimos los tests que se añadiran a la suite tomando en cuenta algunas consideraciones, enumeradas a continuación.

1. Los tests son escritos usando requerimientos definidos desde el punto de vista del cliente.

Hasta hace algunos meses mantenía la práctica comunmente aceptada de escribir pruebas unitarias (unit tests) y pruebas de integración (integration tests) de forma separada. Las pruebas unitarias se enfocaban en funciones individuales dentro de un módulo, mientras que las de integración reunían varias funciones y sus interacciones. Un ejemplo se muestra en la siguiente figura.

Pruebas unitarias y de integración

Pruebas unitarias y de integración. La forma anterior de escribir los tests.

Recientemente hemos cambiado ese enfoque y nos concentramos en escribir tests que reflejan directamente los criterios para la aceptación de la historia o para cumplir con el comportamiento deseado en el caso de un defecto. Dicha forma de escribir los tests está enfocado desde el punto de vista del cliente de la API y trata de validar su comportamiento. Un ejemplo se muestra en la siguiente figura.

Prueba en base a los criterios para aceptar una historia o solución de defecto

Test en base a los criterios para aceptar una historia o solución de defecto.

Este cambio trae consigo varios beneficios:

  • Menos búsqueda de defectos: el código es verificado en base a sus especificaciones.
  • Se establece un contrato con el cliente: la funcionalidad no cambia a menos que los criterios cambien, de lo contrario los tests comienzan a fallar.
  • Menos cambios en las pruebas: si en algún momento decidimos reemplazar una función por otra más óptima no tenemos que escribir tests para dicha función sino que debe responder conforme a los ya escritas para mantener el contrato con el cliente.
  • La documentación del producto mejora. Dado que escribimos los tests desde el punto de vista del cliente es posible observar las especificaciones de la API.
  • La revisión de código mejora. Nos podemos enfocar en verificar que los tests cumplen con los criterios y comentar al respecto.

2. Cada test es independiente de los otros.

Cada test contiene la inicialización de su contexto, su ejecución y su verificación de resultado. Es posible usar funcionalidades genéricas para la inicialización del contexto siempre y cuando sean claras y simples.

3. Un test es equivalente a un comportamiento.

Evitamos más de un comportamiento en cada test. Dicho comportamiento es validado mediante el estado de la aplicación y no sus interacciones.

4. Los tests deben ejecutarse rápidamente.

Una de las formas de lograr rapidez es evitar cualquier interacción con sistemas externos. Cuando una funcionalidad puesta a prueba requiere llamar a otro sistema externo preferimos usar fakes (por ejemplo para mongodb) o stubs para emular ciertas respuestas de los sistemas externos.

La ejecución

Actualmente contamos con 3 entornos para las aplicaciones.

  • Develop: es el reino del ingeniero de software. Es donde es libre de implementar versiones incompletas sin afectar ningún procedimiento.
  • Staging: es un entorno similar a producción donde el ingeniero de calidad valida la correcta implementación de los tickets y la correcta ejecución del sistema en su conjunto.
  • Producción: donde reside el sistema que sirve a nuestros usuarios.

La suite se ejecuta en los siguiente casos:

  1. Cuando el ingeniero de software escribe una merge request en Gitlab solicitando una revisión de código antes de integrar un cambio en develop o en staging.
  2. Cuando la integración es aceptada, verificando que el cambio no ha introducido problemas al no interactuar correctamente con el estado actual del código.

De esta manera intentamos tener un ciclo de retroalimentación corto y podemos ser capaces de encontrar defectos rápidamente.

Manteniendo la suite

Considero que mantener la suite agregando más y mejores tests es el gran reto que tenemos como equipo. El factor principal se encuentra en que la cultura de las pruebas no es algo que pueda ser construido de la noche a la mañana.

En algunos casos convencer al ingeniero de software acerca de los beneficios de escribir pruebas para su código es en sí ya un gran reto. Dado que el equipo es pequeño aún puedo ejercer mi influencia con cada uno de los miembros y hablar al respecto en nuestras reuniones personales.

También existe el proceso de refinamiento en la forma de escribir los tests para que puedan ser realmente valiosos y no sean simples métricas para la vanidad. Es también común encontrarse con tests que verifican resultados que pueden llegar a fallar si ciertas características de su entorno cambian. Todo esto debe ser considerado y discutido a la hora de revisar los cambios en la suite.

Conclusión

La habilidad para desarrollar software de calidad tiene como uno de los componentes principales el ser capaz de encontrar defectos en las aplicaciones de forma rápida. Para lograr esto de forma óptima es necesario implementar una suite de tests automatizados que sean ejecutados ante cada cambio en el código de las aplicaciones.

La forma de escribir los tests en nuestro equipo está basada en el modelaje del comportamiento que deseamos obtener de las aplicaciones y son siempre ejecutados desde el punto de vista del cliente a través de la API pública.

Usamos los criterios que deben cumplir las aplicaciones tanto para nuevas funcionalidades como para los fallos para escribir los tests correspondientes.

Mantener una suite que contenga tests efectivos y eficientes es un gran reto dentro del equipo pero que considero de gran importancia para lograr una mejor funcionalidad y experiencia para el usuario y que es traducido en beneficios para la empresa.

Comments:

El desarrollo de software lean – Blog de Raymundo Vásquez Ruiz -

[…] Pruebas automáticas del software. […]


#### [La relevancia de las pruebas automáticas de software para cualquier empresa 🧪 – Blog de Raymundo Vásquez Ruiz](https://blog.vasquezruiz.me/la-relevancia-de-las-pruebas-automaticas-de-software-para-cualquier-empresa-%f0%9f%a7%aa/ "") -

[…] En mi opinión la mejor manera de escribir pruebas automáticas del software es invocando nuestro si…. Por ejemplo si estamos escribiendo una API implica realizar pruebas invocando nuestras rutas y evitando realizar pruebas para funciones intermedias, de esta manera creamos un contrato con los usuarios. […]