¿Para qué monitorizar la calidad? Aspectos, scores, KPIs y otros duendes

Introducción

Después de tanto tiempo sin escribir en el blog, vuelvo a aparecer para cumplir mi última promesa antes de año nuevo! Espero que estés genial dentro del año que hemos pasado, sino es así te mando mucha fuerza.

Si lees la palabra testing o calidad, es probable que lo primero que te haya venido a la cabeza es la palabra “test” o prueba, como si el desarrollar los teses fuera el objetivo principal de una estrategia de calidad. Esto es normal, y la razón es porque estamos muy acostumbrados a pensar que con tener una buena cantidad de pruebas vamos a mejorar la “calidad”.

Pero, ¿qué es la calidad?, ¿No tener bugs?. ¿Es el bug el indicador principal de la calidad de nuestras aplicaciones?

En este post me gustaría hablar sobre los aspectos que creo que definen la calidad de nuestras aplicaciones, cómo monitorizar la estrategia de testing y cómo ayudarnos en la toma de decisiones.

Aspectos de la calidad

Como he comentado en la introducción, creo que la calidad no debería basarse únicamente en si nuestro producto tiene muchos o pocos bugs, estoy de acuerdo en que es un aspecto importante, pero tenemos que tener un prisma más holista.

En mi caso separo los aspectos de calidad en tres grupos: funcionales, técnicos y productivos.

Aspectos funcionales

Son aquellos que evalúan que el producto se comporta como el usuario/cliente o negocio lo espera. Por ejemplo, podríamos evaluar que el comportamiento es el esperado, la UX etc.

En este post no voy a entrar al detalle de los KPIs para evaluar los aspectos funcionales ya que creo que puede ser interesante poner el foco en los siguientes. ¡Perdonadme! 

Aspectos técnicos

Son aquellos que evalúan la calidad técnica del producto. Estaríamos hablando por ejemplo de vulnerabilidades, code smells, código duplicado, complejidad ciclomática y arquitectónica, deuda técnica etc.

Aspectos productivos

Muy poco valorados en el testing, son aquellos que nos ayudan a medir si el producto bloquea o no a la productividad del equipo. Por ejemplo podríamos evaluar cuánto tiempo nos lleva corregir un bug, añadir una nueva funcionalidad, falsos en los tests etc.

Cómo veis, no hemos hablado de bugs como tal en ninguno de los aspectos. Este punto es interesante y abre el debate de lo que consideramos como bug y en qué aspectos recaería este concepto. 

Si consideramos el bug únicamente como algo técnico, es decir, un cambio en el código que provoca posibles fallos o errores, lo podemos ubicar en el aspecto técnico. Pero, ¿Y si ese fallo es debido a una falta de definición o un corner case lo llamamos “bugature”?

Se está creando una tendencia a categorizar los bugs, por ejemplo: bug técnico, bug en producción o en desarrollo, bug de infraestructura, bug de definición etc. Esto nos ayudaría a poner el foco y encontrar el punto de mejora mucho más fácil. Cómo he dicho, esto da para un buen debate.

Tenemos que cambiar nuestra forma de pensar y de entender la estrategia de calidad. Debemos darnos cuenta de que las técnicas de testing las aplicamos no sólo para encontrar o prevenir los bugs, sino para garantizar de alguna manera estos aspectos y la productividad del equipo.

¿Entonces, no desarrollamos las pruebas solo para encontrar o prevenir bugs? No. No dejes que el árbol no te deje ver el bosque, toma frase de abuelo cebolleta.

KPIs y el score de calidad

Vamos a la parte interesante. ¿Qué KPIs seguimos para evaluar todos estos aspectos y qué “demontres” es eso del score de calidad? 

Me gustaría decir que a día de hoy he llegado a evaluar todos los aspectos que he comentado en la introducción con KPIs, pero como os he dicho, la realidad es que no es así. Solo he tenido oportunidad o solo he conseguido evaluar algunos de ellos. 

KPIs de los aspectos técnicos

En la parte técnica es donde suelo tener mayor número de KPIs dado que son más fáciles de obtener y evaluar los datos.

  • Número de bugs vivos. Los bugs vivos los identifico como aquellos que no están en un estado resuelto. Cuando este KPI crece es realmente interesante ver si es porque el producto se degrada, o porque tenemos que mejorar la gestión del panel de bugs dentro del equipo.
  • Número de bugs vivos VS tareas vivas. Es un KPI interesante para ver dentro de todas las tareas que tenemos que parte de la tarta se las lleva los bugs. A día de hoy he dejado de usar este KPI ya que realmente no lo tenía en cuenta para la toma de decisiones.
  • Número de bugs creados por prioridad. Realmente no nos interesa hablar de cantidad, sino de prioridad o de impacto.
  • Número de bugs resueltos por prioridad. Al igual que el KPI anterior, nos interesa saber el número por prioridad o impacto, ya que realmente es lo que nos va a hacer decidirnos que bug solucionamos primero.
  • Estado del análisis estático. Este dato es un agregado de otros KPIs. Por ejemplo con una herramienta como Sonar podemos evaluar el estado del código: vulnerabilidades, code smells, seguridad, mantenibilidad, código duplicado, complejidad, cobertura etc.

En este punto me gustaría recomendaros utilizar pruebas de mutación, ya que el análisis estático nos va a evaluar el resultado de su ejecución, viendo así la calidad de nuestras pruebas. Este dato si lo analizamos junto con la cobertura, realmente tendremos un resultado bastante más objetivo que lo que es realmente analizar  la propia cobertura.  

KPIs de los aspectos productivos

Las estrategias de testing no solo tienen que ayudarnos a prevenir el número de bugs, también deben ayudar al equipo a ser más productivos. Tenemos que conseguir una estrategia que equilibre la calidad y productividad. 

  • Tiempo de resolución de bugs por prioridad. Importante para ver si estamos resolviendo los bugs en los tiempos estimados por prioridad o simplemente estamos priorizando bien.
  • Número de bugs descartados. ¿Estamos creando bugs que no lo son?, ¿Reproducimos los bugs antes de darlos de alta?  Este KPI nos va a dar el estado de la calidad de nuestro panel de bugs.
  • Puntos de historia desarrollados. Puede ser interesante si queremos saber si los cambios en nuestra estrategia de testing están afectando al delivery. Este es uno de los KPIs con los que más dudas he tenido en implementar ya que no es del todo determinista, pero sí puede servir como alerta.
  • Números de tareas no validadas. Este KPI es uno de los más importantes de cara a valorar si la estrategia preventiva funciona. Vamos a ver cuantas tareas se echan atrás en el proceso de code review por un bug en el código, y por qué no lo han detectado las técnicas preventivas.
  • Falsos positivos/negativos en las pruebas. Es un KPI que puede ayudarnos a valorar tanto la calidad de nuestras pruebas como el impacto en la productividad que tienen. Realmente no lo he llegado a implementar ya que el decidir si los resultados de las pruebas son falsos o no, puede ser un proceso manual. A día de hoy estoy dando vueltas para ver si es interesante implementarlo.

Score de calidad

Ya hemos visto el número de KPIs que podemos utilizar para valorar la calidad de nuestro producto, pero ¿realmente vamos a saber utilizar tanta información y tanto numerito para hacer una evaluación?

Donde trabajo actualmente hemos creado un sistema donde podemos definir un perfil de reglas que puntúan los diferentes KPIs, devolviendonos el score del producto. De esta forma evaluamos objetivamente el software y vemos su evolución. Si observamos que el score del producto se degrada, con entrar a ver la puntuación asignada por cada KPI veremos donde está el problema y podemos tomar acciones.

De forma resumida así es más o menos como funciona nuestro sistema:

  1. Damos de alta el proyecto que queremos analizar en el sistema.
  2. Asignamos un nuevo “minero” al proyecto para que se ejecute cada X horas y extraiga la información de las tareas y los bugs del proyecto.
  3. Cada resultado del análisis estático del proyecto se enviará al sistema.
  4. Cada vez que el proyecto se actualice con nueva información de calidad, el algoritmo re-calculará el score en base a un perfil de reglas que se le ha asignado al proyecto. 

Un ejemplo de perfil de reglas (score profile) podría ser:

En nuestro caso la puntuación de cada proyecto va de 0 a 100, asignándole una label de calidad, A, B, C o D, dependiendo el valor del score.

De momento los scores de calidad nos están dando buen resultado para ver cómo afecta la estrategia de calidad al proyecto. 

Otra recomendación que os doy, es que si trabajáis con OKRs de calidad podéis utilizar el score como OKR ya que agrupa diferentes KPIs, es totalmente medible y es fácil poner objetivos alcanzables.

Analizando los datos para nuestra estrategia

El score como norma

Como hemos dicho anteriormente lo interesante es ver la evolución del score del producto y poder corregir a tiempo su degradación. Si observamos que el score baja podemos ver en detalle la evaluación del algoritmo y tomar las acciones que creamos necesarias para revertirlo.

Analizando los KPIs en detalle

A parte del score, también es interesante tener una visión en detalle de los KPIs y sus tendencias. Esto siempre nos puede ayudar poner el foco y valorar los cambios que tenemos que hacer en la estrategia de testing. 

Ejemplos:

  • El número de bugs aumenta y los code reviews suelen ser positivos. Puede ser que necesitemos invertir esfuerzos en la mejora de las pruebas, puede ser que tengamos que mejorar el proceso de code review etc.
  • El tiempo de resolución de los bugs de prioridad media es muy alto. Puede ser debido a que el equipo no gestiona bien la prioridad, puede ser que no se invierta puntos de historia en el sprint para solucionar bugs etc.

Veamos otro ejemplo, esta vez con un análisis de las tendencias. El siguiente gráfico muestra la evolución de los bugs creados, resueltos y rechazados.

  1. Vemos como en el primer punto el pico de bugs se dispara. Un primer análisis puede indicarnos que no se han invertido esfuerzos en implementar una estrategia de testing.
  2. Como primera acción se decide implementar técnicas reactivas y reducir el número de bugs, por lo que la tendencia baja, pero no tomamos medidas preventivas.
  3. El decidir no invertir esfuerzos en técnicas preventivas hace que el pico se vuelva a elevar. Por lo que se decide esta vez sí invertir esfuerzos en medidas preventivas.
  4. Tras aplicar una estrategia de testing preventiva vemos como el producto se va poco a poco estabilizando.

Todos estos datos nos ayudan a entender cómo afecta nuestra estrategia de testing al producto, es una forma de evaluarla. Pero no nos engañemos, tenemos que hacer un análisis más profundo del asunto, ya que también saca a relucir otro tipo de puntos de mejora, por ejemplo en la gestión del equipo o del producto.

  • ¿El no tener una estrategia de testing ha podido ser por falta de responsabilidad en el equipo, por prisas por sacar un producto o una funcionalidad?
  • ¿No tenemos una buena cultura de calidad?
  • ¿No se han definido bien las historias?

Y un largo etc, es decir, tenemos que hacer un análisis holista y por supuesto no podemos utilizarlos para juzgar, sino para buscar puntos de mejora. 

Conclusiones

Si habéis llegado hasta aquí puede ser que os haya interesado al menos un poquito el post, cosa me alegra!

Como conclusión me gustaría recalcar que tenemos que tomar los KPIs o el score como un sistema de control y alerta que nos indique si tenemos que hacer cambios en cómo aplicamos las técnicas de testing.

Tenemos que ser abiertos y entender que cada producto y equipo es diferente y lo que funciona en uno, no tiene porque funcionar en otro. Ninguna estrategia es una panacea y lo normal es que sea viva, se adapte y evolucione. ¿Podríamos llamarlo relatividad estratégica? ¡Me gusta la idea!

Tenemos que empezar a pensar que el testing no solo es para reducir el número de bugs, sino también lo es para ayudar a mejorar y optimizar la productividad y seguridad del equipo.

En mi caso la pelea con los KPIs es continua, es decir, lo que hoy me funciona, mañana igual no, es por eso que os invito a probar a implementar nuevos y a no tener miedo de descartar aquellos que creais que no os valen. 

Otro consejo que a mí me ha ayudado mucho a mejorar la cultura de la calidad en los equipos y promover la responsabilidad compartida es visibilizar y hacer partícipe al equipo de este dashboard. Si el equipo lo tiene presente y ven que van mejorando los datos o que un “para qué voy a meter un test unitario” hace que el score se degrade, les va a sensibilizar y a concienciar.

Creo que estos datos enfocados de otra manera, pueden ser muy interesantes para mostrar a negocio, también para que entiendan el esfuerzo que se hacen en el equipo y la importancia de que las prisas no son buenas o que la calidad no es algo que se pueda sacrificar.

¡Y esto es todo!

¡Feliz Solsticio de Invierno, Navidad, Hanukkah o lo que vuestras costumbres dicten!

Abstracta Webinar: Diseñando una estrategia preventiva mediante pruebas aisladas e integradas

Introducción

A últimos del mes pasado fui invitado por Abstracta para participar dando un webinar en sus tech talks. Aquí os dejo su canal de YouTube.

La verdad es que fue una experiencia muy agradable, por varios motivos. El primero de ellos, es por poder participar con grandes amigxs que me han apoyado en la creación de este blog, Federico Toledo, participando incluso con algún post, o que han participado en la comunidad de NorthemQuality como Lisandra Armas.

Otro de los motivos es por poder presentar en la charla y con ejemplos, lo que os llevo hablando en este blog durante un tiempo. En una hora no da tiempo de hablar de todo lo que me gustaría, pero sin duda me quedé más que satisfecho. Siempre se escapa algún efecto demo, pero lo salvamos bien 😜. Así que os lo agradezco de ❤️.

Se que quedan muchas cosas por investigar y por crecer en este area de las estrategias preventivas y las pruebas aisladas, pero hay que dejar espacio a otros temas y no monopolizarlo. Ahora toca investigar otras cosillas para el blog, pero eso no quita que de vez en cuando escriba algo al respecto!

Por último os dejo abajo el video de la charla y el enlace a la presentación y repo!

https://slides.com/aaguila/designing-a-preventive-strategy#/

https://github.com/QAJungle/isolated-test-examples

Video

Dimensiones entre pruebas aisladas e integradas. Flakiness de las pruebas

INTRODUCCIÓN

Seguimos con la serie de “Dimensiones entre pruebas aisladas e integradas”. En los post de la serie anteriores hemos hablado sobre el grado de confianza de las pruebas y del tiempo de test de las pruebas. Vimos como el tener un mayor área de impacto ayudaba a tener un mayor grado de confianza y como el tiempo de test de las técnicas de testing es un valor que puede declinar la balanza en las decisiones de nuestra estrategia.

Existe otro punto importante en el que debemos basar las decisiones de nuestra estrategia de testing. En este post hablaremos sobre el test flakiness de cada tipo de pruebas, y al igual que en los post anteriores pondré el gráfico de dimensiones comparativo de cada tipo de pruebas.

TEST FLAKINESS

Cuando hablamos de “flaky tests” hablamos de debilidad, es decir, de la capacidad de que las pruebas fallen con facilidad por razones externas a los cambios realizados. Los flaky tests son uno de los quebraderos de cabeza más grandes del mundo del testing, sobre todo del testing funcional.

La debilidad de las pruebas pueden venir por diferentes motivos, los llamaremos flaky points o puntos de debilidad: conexión, estrategía de datos de prueba, infraestructura etc.

Puntos de debilidad

¿Cuántas veces hemos comenzado a desarrollar pruebas sin poner atención en la arquitectura del proyecto o en la arquitectura de test que tenemos planteada? En mi caso, me ocurría mucho. 

La arquitectura de test que tengamos planteada en nuestra aplicación es de suma importancia a la hora de desarrollar pruebas, dado que nos marcará no solo las necesidades de testing que tenga el proyecto, si no algo igual de importante, los puntos de debilidad.

Los puntos de debilidad o flaky points son aquellas partes o áreas del código, arquitectura y de las pruebas que pueden ser propensas a fallar debido a razones externas a nuestro código o nuestros cambios.

Los puntos de debilidad pueden ser muy variados, dependiendo de las características de nuestros proyectos, pero principalmente solemos encontrarnos con:

  • Datos: Uno de los problemas más comunes si no tenemos una buena estrategia de datos es que las pruebas fallen debido al conflicto de los datos y las dependencias entre las diferentes pruebas. Esto suele ser debido a reutilizar datos, a tener un repositorio compartido etc.
  • Infraestructura: Otro fallo común por ejemplo en arquitectura en microservicios es cuando necesitamos tener todos los servicios que necesitamos desplegados y con la versión correcta. En muchas ocasiones nos encontramos que eso no es así, debido a muchos motivos, entre ellos que tengamos que competir por el mismo entorno de pruebas y exista el conflicto entre versiones. 

    Puede ocurrir también que haya parte de la infraestructura que necesitemos que no esté bien levantada o versiones de sistemas de bases de datos etc. 

    En resumen, nos podemos encontrar con un espectro muy amplio de problemas.
  • Comunicación: Los fallos de red suelen ser un problema en el que nos tengamos que enfrentar en ciertas ocasiones. Otro problema puede ser el tiempo de carga, el tiempo de respuesta, lidiar con asincronía etc.

    Imaginemos una web, pongamos que tardamos casi un segundo en obtener los datos de una consulta y popular la tabla en una vista con estos datos, puede que nuestra prueba falle debido a que intenta comprobar la existencia de los datos antes de que se obtengan. 

En la imagen vemos identificados los diferentes puntos de debilidad dentro de nuestra arquitectura, una imagen en mente nos debería ayudar a definir la estrategia de testing que buscamos. Es importante tenerlos localizados para comenzar a tomar decisiones que ayuden a paliar estos puntos.

Una de las formas de paliar y reducir los puntos de debilidad de las pruebas es aislarlas. Aislando las pruebas reducimos notablemente estos puntos ya que no necesitamos comunicarnos con los colaboradores externos, los datos de prueba deberían estar acotados únicamente a la prueba y la infraestructura se levanta ad-hoc a la prueba.

Una cosa importante a destacar es que el punto de debilidad de datos lo podemos heredar en las pruebas aisladas si no seguimos una buena estrategia de datos aislada. Puede que se minimice el impacto debido a que la base de datos no es compartida entre diferentes proyectos o equipos, pero sí que podemos llegar a tener dependencia de datos entre nuestras pruebas, manteniendo así el punto de debilidad de datos.

Comparando el flakiness entre los tipos de prueba

Bueno, ya tenemos claro lo que es el flakyness y lo que son los puntos debilidad, ahora toca medirlo junto a otras dos dimensiones:

  • Flakiness, representado por círculos con más o menos radio, en base al grado de debilidad de la prueba.
  • Ámbito (scope) de las pruebas, en el eje X. Se trata de comprobar una parte del código, una funcionalidad concreta o un E2E.
  • Etapa (stage) de las pruebas, en el eje Y. Fase en la que se lanzan las pruebas en local durante el desarrollo, en el CI, o en fases de preproducción o producción.

CONCLUSIONES

Durante toda la serie de post, hemos visto diferentes dimensiones que nos pueden ayudar a tomar la decisión de cuándo implementar o si llegar a implementar una técnica de prueba en nuestra estrategia.

Diseñar una estrategia de testing no es fácil. No se resume en tener una suite de pruebas unitarias, integración, funcionales etc. gigantesca, dado que esto nos puede llegar a perjudicar la eficiencia y la productividad del equipo. Tenemos que llegar a balancear todos los aspectos y llegar a un balance entre productividad y calidad.

Este balance lo podemos ganar a través de implementar una estrategia de testing basado en la prevención, con más técnicas aisladas para obtener un feedback temprano del estado de la calidad de nuestra aplicación. Necesitamos también tener técnicas integradas como pruebas de soporte en etapas más reactivas, de forma que nos ayuden a obtener una mejor visión de la calidad del software pero sin llegar a parar o a bloquear las releases.

Espero que la serie os haya parecido de interés y que os ayude a la hora de definir las estrategias de testing, o a entender que diseñarla no es tarea fácil.

POSTS DE LA SERIE

1/3 Dimensiones entre pruebas aisladas e integradas. Grado de confianza.

2/3 Dimensiones entre pruebas aisladas e integradas. Tiempo de test.

3/3 Dimensiones entre pruebas aisladas e integradas. Test flakiness.

Dimensiones entre pruebas aisladas e integradas. Tiempo de test.

INTRODUCCIÓN

Seguimos con la serie de “Dimensiones entre pruebas aisladas e integradas”!. En el post anterior hablábamos sobre el grado de confianza de las pruebas y cómo el tener un mayor área de impacto ayudaba a tener un mayor grado de confianza.

Para diseñar o definir nuestra estrategia de pruebas no nos podemos basar solo en el grado de confianza, es necesario tener en cuenta otras dimensiones. En este post hablaremos sobre el tiempo de test e iteración de cada tipo de pruebas, al igual que en el post anterior pondré el gráfico de dimensiones comparativo de cada tipo de pruebas.

TIEMPO DE TEST E ITERACIÓN DE LAS PRUEBAS

Antes de ver el gráfico de dimensiones, lo primero que tenemos que entender es cómo medimos el tiempo de test.

Tiempo de test

El tiempo de test es el tiempo que tarda la prueba desde que se lanza hasta que obtenemos los resultados, sencillo, ¿no?. Normalmente lo podemos medir por:

Test time = Build time + Deployment time + Test setup time + Execution time + Test clean time +  Report time.

Resumido en:

TT = BT + DT + ST + ET + CT + RT

No todos los tipos de prueba suman estos tiempos, por ejemplo las pruebas unitarias no tienen tiempo de despliegue, por lo que, DT = 0. 

Otro ejemplo son las pruebas funcionales aisladas, que al tiempo de test hay que añadir el tiempo que tardamos en levantar (EUT – Environment up time) y tumbar (EDT – Environment down time) el entorno aislado. Podríamos poner las siguientes formulas por tipo de prueba:

  • Unit test: TT = BT + ST + ET + CT + RT
  • Contract test: TT = BT + ST + ET + CT + RT.

    El ST ya contempla el tiempo que tarda en descargarse la nueva versión del contrato en caso de que haya.
  • Integrated integration test: TT = BT + ST + ET + CT + RT
  • Isolated integration test: TT = BT + EUT + ST + ET + CT + EDT + RT
  • Integrated functional test: TT = BT + DT + ST + ET + CT + RT
  • Isolated functional test: TT = BT + EUT + ST + ET + CT + EDT + RT

    En las pruebas aisladas lo normal es no desplegar la aplicación, si no levantarla como parte del entorno, por eso el tiempo de despliegue se incluye en EUT.
  • Support functional test: TT = BT + DT + ST + ET + CT + RT
  • Exploratory test: TT = BT + DT + ST + ET + CT + RT
  • Production functional test: TT = ST + ET + CT + RT

En sí estas fórmulas no nos dicen mucho, pero nos pueden servir para conocer donde se van los tiempos de nuestras pruebas. Algo curioso es que por el hecho de tener más variables en la fórmula no significa que el tipo de prueba sea más lento que otra que tenga menos variables.

Los tiempos de las pruebas aisladas contemplan EUT y EDT, que no están contempladas en las pruebas integradas, pero estas últimas son mucho más lentas. Esto es debido a que en las integradas en el tiempo de ejecución (ET) hay que contar que se pueden comunicar con una BD real y con otros colaboradores como servicios etc, llevándose la mayor parte del tiempo.

En la imagen vemos como las pruebas aisladas al conectarse en local contra un snapshot de BD y contra los stubs de los servicios, el tiempo de comunicación se reduce bastante.

La BD únicamente tendrá los datos necesarios de la prueba, y el stub del servicio simplemente nos devolverá la respuesta que esperamos, es decir, no tenemos que esperar a que se ejecute nada en los servicios externos.

Comparando el tiempo de test entre tipos de prueba

Ahora que ya entendemos en qué nos basamos para valorar el tiempo de test vamos a medirlo junto a otras dos dimensiones:

  • Tiempo de test, representado por círculos con más o menos radio, en base al tiempo total.
  • Ámbito (scope) de las pruebas, en el eje X. Se trata de comprobar una parte del código, una funcionalidad concreta o un E2E.
  • Iteraciones (iteration) de las pruebas, en el eje Y. Cada cuanto ejecutamos las pruebas, cada cambio, antes de cada commit, en el CI, en el entorno de testing, pre-producción o planificadas o disparadas por algún evento en concreto.

CONCLUSIONES

Lo más interesante de ver a este nivel, es lo unido que está el tiempo de test con el número de iteraciones. 

Para que el testing ayude a mejorar la productividad del equipo, la idea es tratar de obtener de forma rápida el estado de la aplicación tras un cambio. Por este motivo las técnicas más rápidas se intentan ejecutar en las iteraciones más tempranas del desarrollo.

En este punto es donde las técnicas de testing aisladas nos van a aportan un mayor valor, ya que nos van a permitir ejecutar en iteraciones tempranas y de forma rápida aquellas pruebas que se deberían ejecutar en etapas posteriores, con un mayor coste temporal y por lo tanto, productivo. 

Si nos basamos en una estrategia de testing preventiva, lo que nos va a interesar es ejecutar la mayor parte de las técnicas de prueba en etapas tempranas. Vamos a intentar ejecutar las pruebas por cada cambio que hagamos o antes de cada commit o merge, lo que nos va a hacer apostar por técnicas con un tiempo de test rápido y con un grado de confianza medio alto.

POSTS DE LA SERIE

1/3 Dimensiones entre pruebas aisladas e integradas. Grado de confianza.

2/3 Dimensiones entre pruebas aisladas e integradas. Tiempo de test.

3/3 Dimensiones entre pruebas aisladas e integradas. Test flakiness.

Dimensiones entre pruebas aisladas e integradas. El grado de confianza.

INTRODUCCIÓN

Tras la charla “Isolated vs Integrated tests” que presenté en el Open Space de la WeCode 2020 pedí feedback a varios compañerxs y amigxs de la comunidad. Entre ellos a Eduardo Ferro, persona muy respetada por su experiencia y con el que he coincidido en varios eventos, además de haber podido participar en un debate en NorthemQuality.

Podéis ver el debate (QA y principios XP, ¿Juntos o Revueltos?) en los vídeos de la primera temporada.

Mi idea principal era presentar esta charla en la T3chFest, pero la descartaron. Menos mal, no me hubiera dado tiempo, además de poder llegar a ser muy densa. Lo primero que me dijo Edu cuando le pedí feedback fue: “No te daba tiempo ni de palo” (aunque creo que lo de “ni de palo” lo he añadido yo a mis recuerdos). 

Edu me comentó que la idea era interesante y que se había apuntado algunas cosas, pero que podía llegar a costar ver las diferencias entre las pruebas integradas y aisladas, en definitiva, que podría llegar a ser un poco lío. 

Me recomendó hacer varios gráficos que representarán la idea que quería exponer, gráficos con varias dimensiones para ver las diferencias entre cada tipo de prueba.

Me puse a darle vueltas, se me ocurrieron varios gráficos con distintas dimensiones y de aquí nació esta serie de posts..

Os dejo un enlace de este mismo blog para aquellas personas que no conozcan de qué tratan las pruebas integradas y aisladas.

En esta serie de posts vamos a hacer la comparativa entre varios tipos de prueba. En el testing existen un número elevado de técnicas, para el artículo he elegido las siguientes:

  • Pruebas unitarias.
  • Pruebas de contrato.
  • Pruebas de integración integradas.
  • Pruebas aisladas de integración: A diferencia de la pruebas de integración, en las aisladas en vez de conectar con los colaboradores reales, vamos a conectar con componentes (stubs) para simular su conexión.
  • Pruebas funcionales integradas.
  • Pruebas funcionales aisladas: Al igual que en las pruebas aisladas de integración, haremos uso de stubs para simular la funcionalidad de los colaboradores y así no depender de ellos.
  • Pruebas funcionales de soporte: Nos van a servir para detectar aquellos bugs que no deberían bloquear la release. Suelen emplearse como complemento a las funcionales integradas y aisladas.
  • Pruebas exploratorias.
  • Pruebas funcionales en producción: Pruebas que intentan verificar una funcionalidad en producción, normalmente para comprobar el estado de la aplicación.

Vamos a ello!

GRADO DE CONFIANZA DE LAS PRUEBAS

La dimensión que vamos a tratar en este post es la del grado de confianza de las pruebas. 

Cuando hablamos de grado de confianza, estamos hablando de la capacidad de detección de bugs de una prueba. Lo importante es conocer el área de impacto de la prueba en nuestra aplicación, cuanto más impacte, más grado de confianza podrá darnos. Vamos a diferenciar dos tipos de área de impacto:

  • Área de impacto principal (MIA): Es el área objetivo de la prueba.
  • Área de impacto secundario o área de impacto irradiada (IIA): Es el área que se ve afectada sin ser objetivo principal de la prueba.

Lo vamos a entender mejor en el siguiente análisis por cada tipo de pruebas. En las siguientes imágenes tenemos representada una aplicación con arquitectura hexagonal, veamos las áreas de impacto de los diferentes tipos de pruebas aisladas e integradas.

Área de impacto en pruebas de integración integradas y aisladas

En las pruebas de integración integradas, vemos cómo el área de impacto principal (MIA) afecta a la BD y a la clase que implementa la integración con la BD (repository adapter).

Tiene sentido, puesto que es lo que queremos comprobar en este tipo de pruebas, pero la capa de dominio se ve afectada en nuestra aplicación debido a que en nuestro ejemplo accedemos a las clases de dominio en el repository adapter. Este área es identificada como área de impacto irradiada (IIA).

En las pruebas de integración aisladas, el área de impacto principal afecta al repository adapter. En este caso, el snapshot de la BD pasa a ser un área secundaria ya que no es la BD “real”, por lo que tampoco probamos su configuración. 

Después de ver las áreas de impacto de los dos tipos de pruebas, podemos valorar que el grado de confianza de las pruebas integradas de integración es mayor que el grado de confianza de su homónimo aislado.

Área de impacto en pruebas funcionales integradas y aisladas

En el caso de las pruebas funcionales tanto integradas como aisladas, es más complejo ver o diferenciar entre las áreas de impacto principales e irradiadas, esto es debido a que al comprobar una funcionalidad el MIA abarca casi todo este scope.

En las siguientes imágenes vamos a ver cúal es el área de impacto de una prueba que ataca una funcionalidad concreta, en el caso de una prueba funcional integrada y la misma de forma aislada.

El grado de confianza seguirá siendo mayor en la pruebas integradas, no obstante aislarlas nos dará ciertos beneficios como poder lanzarlas en un entorno local de desarrollo. 

En el caso de la pruebas funcionales de soporte y exploratorias el área de impacto sería el mismo que las que hemos visto en las integradas ya que seguimos con una comunicación real con nuestra BD, servicios etc.


Área de impacto en pruebas de contrato

En el caso de las pruebas de contrato tenemos que valorar el área de impacto dependiendo de si son pruebas de proveedor o consumidor. 

En el caso de las pruebas de proveedor el MIA se focalizará en los controladores, al mockear sus colaboradores no habrá áreas irradiadas. En el caso de las pruebas de consumidor el MIA afecta a la clase cliente (service adapter), pero en este caso la capa de dominio si se ve afectada por el IIA, ya que la clase cliente implementa clases de dominio. 

Área de impacto en pruebas unitarias

En las pruebas unitarias el área de impacto principalmente se focaliza en la clase testeada en el caso de ser unit solitary tests. Por otro lado, en el caso de ser sociable unit test tendemos áreas de impacto irradiadas.

Podéis seguir este enlace para conocer los dos tipos de pruebas unitarias.

Comparando el grado de confianza entre tipos de prueba

Ahora que hemos visto lo que es el grado de confianza por cada tipo de prueba, vamos a ver el gráfico de dimensiones que comentábamos al principio del post. Mediremos:

  • Grado de confianza, representado por círculos con más o menos radio, en base al grado de confianza.

    Es importante destacar que el grado de confianza lo he valorado por la capacidad de impacto del tipo de prueba, por ejemplo, las pruebas unitarias pueden tener impacto en la mayor parte del código.

    Al igual que en el caso de las pruebas aisladas funcionales frente a las funcionales o E2E de soporte, que tendrá un mayor grado de confianza debido a que lo normal es tener un mayor número de pruebas aisladas que pruebas integradas de soporte.
  • Ámbito (scope) de las pruebas, en el eje X. Se trata de comprobar una parte del código, una funcionalidad concreta o un E2E.
  • Etapa (stage) de las pruebas, en el eje Y. Fase en la que se lanzan las pruebas en local durante el desarrollo, en el CI, o en fases de preproducción o producción.

CONCLUSIONES

El grado de confianza no debería darnos a elegir entre un tipo de prueba u otra, como vemos en el gráfico, cada prueba tiene un scope y un stage diferente, es por eso que son complementarias unas con otras. Por el contrario, sí nos puede ayudar en definir nuestra estrategia de testing.

Las pruebas aisladas deberían estar más presentes en las fases tempranas del desarrollo, de esta forma vamos a poder desarrollar de forma más fiable y destapar cuanto antes los bugs más críticos o bloqueantes. 

Las pruebas integradas deberían ayudarnos a destapar aquellos errores que vengan por infraestructura o aquellos que no sean bloqueantes. Deberían ser pruebas de soporte que nos ayuden a obtener mayor información sobre el estado de nuestra aplicación.

No obstante cómo he dicho, la estrategia de testing que sigamos debe estar alineada con el contexto situacional. La estrategia puede y debe ir pivotando y creciendo de forma progresiva, adaptándose poco a poco.

POSTS DE LA SERIE

1/3 Dimensiones entre pruebas aisladas e integradas. Grado de confianza.

2/3 Dimensiones entre pruebas aisladas e integradas. Tiempo de test.

3/3 Dimensiones entre pruebas aisladas e integradas. Test flakiness.

P&R – Balancear la productividad del equipo y la calidad del producto

INTRODUCCIÓN

Ya hemos hablado anteriormente en este blog sobre la estrategia Prevention & Reaction (P&R) y cómo aplicarla en el equipo con un rol como el QDev.

Ya comentamos de la importancia de que fuera una estrategia viva y adaptable, es decir, que fuéramos capaces de pivotar sin ver afectada la calidad ni la productividad del equipo.

Pero, ¿Cómo la controlamos o monitorizamos su estado?

Donde trabajo actualmente llevo unos meses intentando crear la cultura y la estrategia de calidad. Al principio hemos tenido que definir unos KPIs muy generales y monitorizar la estrategia de forma manual. 

Como comienzo para ir aplicando e iterando en la estrategia no era una mala opción, pero hemos evolucionado. Se ha conseguido que los equipos sean más autónomos aplicando la estrategia definida, por lo que ya no nos vale monitorizar así. 

Contaré mi experiencia sobre cómo aplico el de rol de Head of QA en otro post 😛

P&R se apoya mucho sobre el concepto de smart testing, por lo que tenemos que hacer una monitorización inteligente y con decisiones automáticas basadas en datos.

En esta serie de posts hablaremos de dos conceptos importantes dentro de la estrategia P&R:

  • Balancear la red de seguridad de calidad y la productividad del equipo
  • KPIs y monitorización de la estrategia

Empezaremos por el primer concepto.

¿Qué tiene que ver la productividad con la calidad?

Bajo mi punto de vista y en nuestra estrategia, mucho. P&R se basa principalmente en la prevención, y las técnicas preventivas operan en la etapa de definición y desarrollo, por lo que tienen impacto directo sobre la productividad del equipo. 

La técnicas de testing que apliquemos no solo van a ayudar a “garantizar la calidad” del producto, si no, que van a ayudar a desarrollar con más seguridad y por tanto de una forma más eficiente.

Si abogamos por una responsabilidad compartida de la calidad en el equipo, no va a existir un rol (Tester, QA, QE, Test Engineer etc.) que sea el único en aplicar las técnicas de testing o en automatizar las pruebas  y gestionar bugs.

Todo el equipo tendrá que aplicarlas y desarrollar las pruebas junto con el QDev, quien se hará cargo de la estrategia de calidad del equipo o del producto.

Muchos conocemos la discusión en la comunidad sobre externalizar el testing fuera de la empresa o incluso tener un equipo de calidad dentro y trabajar en un equipo multidisciplinar, pero de lo que no se habla tanto es de que también se externaliza el testing dentro de un equipo multidisciplinar. 

Veamos un ejemplo:

Tenemos un equipo compuesto por 1 QA vs 4 Devs, y en la que la responsabilidad del testing (salvo los code review y unit/integration testing) es del QA. Entre sus tareas está la de gestionar los bugs, diseñar y automatizar pruebas, validar las issues, hacer testing exploratorio etc.

Cuello de botella en el flujo de trabajo

La velocidad de desarrollo siempre será mayor que la del QA, generando un cuello de botella y como resultado:

  • Mala eficiencia 
  • Pérdida de calidad en el producto.
  • Mayor frustración.

Podemos decir, metemos más personas de QA y por tanto reducimos el cuello de botella, todos sabemos que la matemática no es perfecta en estos casos. 

¿Cómo balanceamos la productividad con el desarrollo de la red de seguridad?

¿Los desarrolladores tienen que hacer testing? Es una de las preguntas que pueden surgir en debate. 

Bajo mi opinión, la respuesta es, sí. Si creemos que el desarrollador tiene que hacerse cargo de la tarea desde que la comienza hasta que está en producción, tendrá que cerciorarse de que sale con calidad. 

Es decir, desarrollar la funcionalidad, diseño y desarrollo de las pruebas necesarias (unitarias, integración, funcionales, performance etc) y validar la issue etc, forma parte de la tarea y es responsabilidad del desarrollador y el code reviewer. 

Esto no quiere decir que el QDev (en este caso) no tenga que hacer testing, claro que tiene que hacerlo. Su responsabilidad recae en crear la red de seguridad, para la que desarrollará herramientas y utilidades (las pruebas son consideradas herramientas) así como liderar la estrategia y la cultura de calidad dentro del equipo.

Lógicamente esto tiene un coste en lo que la estimación de la tarea se refiere, ya no solo es desarrollar la funcionalidad, por lo que una tarea que tuviera un coste subjetivo de talla M, tendría una talla objetiva de L. 

¿Porqué hablo de coste subjetivo? Veamos:

Coste subjetivo en la estimación

Coste subjetivo en la estimación de la tarea

Lo normal es estimar cuánto se tarda en desarrollar, y en el mejor de los casos también se asume el coste del CR y el despliegue a prod. Pero el problema viene en que no asumimos el coste del testing muchas veces al no estar integrado en el trabajo del desarrollador, por lo que el coste estimado de la issue no se acercará a la realidad. 

Como vemos en la imagen, es prácticamente imposible estimar de forma objetiva si no se integra el testing en la fase de desarrollo, ya que se depende de la finalización de una tarea de la que es totalmente dependiente.

Si nos fijamos, esa dependencia causa un cuello de botella cada vez mayor, esto es debido a que el desarrollador necesita que se valide su issue, una vez ya la ha desarrollado, haya pasado el CR y haya desplegado en un entorno de pruebas. 

En caso de un feedback negativo, deberá volver a la fase de desarrollo, CR, deploy a pruebas y volver a repetir el proceso. Un coste productivo bastante alto.

Yo siempre digo que para mí, el “fracaso” no está sólo en encontrar un error o un bug en producción, si no en el entorno de pruebas, debido a que solucionarlo tiene un coste alto, menor que el de producción, claro está. 

Es por eso que creo en la necesidad de invertir en técnicas preventivas.

Coste objetivo en la estimación

Coste objetivo en la estimación de la tarea

Por el contrario, si se ve la tarea como el conjunto del desarrollo de la funcionalidad y el diseño, desarrollo y ejecución de las pruebas, a cargo del desarrollador, mejoraremos la eficiencia y nos acercaremos más al coste objetivo de la tarea.

Lo más importante de seguir esta metodología en cuanto al testing, es que vamos a tener un feedback temprano en fase de desarrollo, y no en fases posteriores.

Las pruebas dejan de ser jueces y pasan a ser la red de seguridad de calidad. Incluso los desarrolladores pueden trabajar con TDD, BDD etc. 

La probabilidad de encontrar un fallo o un bug en fases de pruebas posteriores se verá reducida ya que se habrán detectado y arreglado en fase de desarrollo, siendo el coste productivo mucho más bajo.

El o la QDev intentará equilibrar el coste productivo y la calidad mediante el desarrollo de herramientas de testing y la estrategia de calidad del equipo.

El equipo

Para poder llegar a trabajar con este modelo, es necesario que exista una cultura de calidad dentro del equipo. Los integrantes deberán tener unos conocimientos mínimos de testing.

¿Esto quiere decir, que hay contratar desarrolladores con conocimientos de testing? No necesariamente. 

El QDev tiene la responsabilidad de crear la cultura de testing, y por tanto de formar al equipo.

Cuando la responsabilidad del testing no es compartida, hemos visto cómo puede ocurrir que la productividad del equipo se vea mermada y por tanto la calidad se vea comprometida. 

Vamos a ver dos gráficos donde se muestra la tendencia del valor de calidad-productividad frente al coste de desarrollo de calidad. Es decir, cuánto cuesta invertir en desarrollo de calidad, frente al valor que nos aporta.

La línea verde muestra el coste de desarrollo de calidad del equipo.

La línea morada muestra el valor de calidad-productividad del equipo.

El primero muestra la tendencia en un equipo donde la responsabilidad no es compartida. El coste de inversión se mantendrá estático, y debido a que es probable que se formen cuellos de botella, el valor de calidad-productividad llegará un momento en el que irá descendiendo.

Coste de desarrollo de calidad vs valor productividad-calidad

El segundo muestra la tendencia en un equipo donde la responsabilidad es compartida y gestionada por un QDev. El coste de inversión será alto hasta que el equipo coja la dinámica y esté formado. A medida que aumenten las skills de calidad del equipo, el coste de desarrollo será menor, y el valor de calidad-productividad irá aumentando.

El trabajo del QDev consiste en ayudar a reducir el coste de desarrollo de calidad y una vez el equipo sea más autosuficiente, potenciar el valor de calidad-productividad.

Coste de desarrollo de calidad vs valor productividad-calidad

Conclusiones

Cuando trabajamos en la estrategia P&R es muy importante balancear la productividad del equipo y la inversión del desarrollo de calidad.

Crear una cultura y responsabilidad compartida de la calidad dentro del equipo ayuda a trabajar de forma más eficiente, pero requiere de uno skills de testing que es probable que el equipo no lo tenga en fases iniciales. 

La labor del QDev es velar por ello. Diseñar una estrategia de calidad que sirva como red de seguridad al equipo, ayudándoles a que trabajar de una forma más eficiente.

P&R es una estrategia viva y cambiante, por lo que es necesario monitorizar para ver en qué punto estamos en cada momento. Para ello será necesario definir unos KPIs que nos sirvan como punto de control.

En el siguiente capítulo veremos cuáles son los KPIs más importantes y cómo monitorizar la estrategia.

El futuro de QAJungle

Hace meses que no escribo nada, que no doy al blog el mimo que se merece. Es un poco triste, ya que el blog ha sido y es un espejo de mi evolución laboral y personal.

¿Las razones?

Una de ellas ha sido un cambio importante en cuanto a trabajo. He querido centrarme e invertir más tiempo en adaptarme al él.

Otra razón es que necesitaba dedicar más de mi tiempo libre a lo que en realidad estaba destinado.

Por último, la falta de ideas. Siempre he querido que QAJungle sea un blog donde existan artículos diferentes a lo que podamos encontrar con una búsqueda en google, innovar (está claro que con los primeros artículos no fué así…), evitar escribir por acumular o por no perder lectores.

Es en parte por estos motivos que creo que es momento de darle un pequeño cambio de sentido al blog, adaptarlo a mi nuevo contexto.

No os voy a mentir, todavía estoy intentando darle forma a su nueva dirección, pero alguna idea ya tengo.

Un saludo.

QDev, ¿Una nueva forma de aplicar el testing?

Introducción

Después de bastante tiempo sin publicar nada debido a que entre otras cosas he estado centrado en el proyecto de la comunidad de NorthemQuality, vengo con un artículo que me hace especial ilusión.

Durante estos dos últimos años, en el equipo hemos tenido que trabajar en varios proyectos que han tenido que hacer que el rol de QA/E tenga que evolucionar a uno nuevo que nosotros mismos hemos definido.

En este artículo me gustaría explicar qué es lo que ha hecho que el rol evolucione y en que ha evolucionado!

El proyecto como punto de inflexión

Todo comenzó cuando tuvimos que enfrentarnos a un proyecto en el que veíamos que íbamos a tener que lidiar contra bastantes infortunios.

El primero de ellos era que no teníamos un product owner para el proyecto por lo que, no íbamos a tener unas tareas bien definidas y por lo tanto, no íbamos a tener unos criterios de aceptación claros.

El segundo era que no había una estrategia de calidad, por lo que el testing que se hacía no era eficiente, y además era un stopper a parte de no tener unos resultados fiables.

Por otro lado, no existía el concepto de equipos multidisciplinares por lo que el testing se hacía por otros equipos que no fueran el equipo owner del proyecto.

Todo esto sumado a otros factores, hacía imaginarnos que la forma de trabajar de la que veníamos como equipo no iba a funcionar.

Nuestro equipo estaba compuesto por un Tech Lead, tres desarrolladores y un QA/E.

La evolución a QDev

Como QA/E era mi responsabilidad el que el producto a parte de responder como se requería. Antes de este proyecto, la forma en la que lo hacíamos era definiendo y desarrollando el juego de pruebas funcionales y mediante la gestión de bugs.

Pero claro… vista la situación a la que nos teníamos que enfrentar, no iba a funcionar.

El equipo siempre ha defendido el modelo estratégico “Prevention & Reaction” que concebí en su día, pero hasta el momento no lo habíamos podido poner en marcha. Igual era la hora de empezar a aplicarlo en la medida de lo posible y comprobar si era viable, había que arriesgar.

Lo primero que hicimos fue pensar como equipo en cómo queríamos trabajar el testing, que necesitábamos y en base a las necesidades, identificar cuál serían las responsabilidad del QA/QE.

Siempre he defendido que el QA/QE en los equipos multidisciplinares debe ser un desarrollador más, al igual que diferenciamos entre fronteder y backender.

De aquí nació el rol de QDev!

El nuevo rol, QDev, tiene que crear una red de seguridad de calidad (QSN) que brinde al equipo la confianza suficiente de desarrollar, para eso debía entre otras cosas debe:

  • Responsabilizarse de definir y aplicar la estrategia de calidad. En nuestro caso nos basamos en el modelo “prevention & reaction”, que va muy alineado al trabajo del QDev.
  • Definir y desarrollar el SUT (system under test) del producto.
  • Trabajar codo con codo con el product owner desde el inicio del proyecto en la definición de los criterios de aceptación. Diseñar el plan de pruebas de cada técnica de testing que posteriormente se desarrollará.
  • Desarrollar las herramientas y frameworks necesarios de testing.

Pero para esto, es muy necesario hacer un cambio de mentalidad y entender que:

  • El QDev es un desarrollador más, especializado en el desarrollo de la estrategia y arquitectura de calidad. Debe hacer partícipe al equipo en las decisiones que se tomen al respecto, siempre de forma consensuada.
  • Todo el equipo es responsable de la calidad del producto. Por ejemplo puede ocurrir que la gestión de los bugs se haga entre todo el equipo.
  • El QDev no es un juez, no dictamina si algo está bien o mal, el es el responsable de desarrollar la QSN que lo hace.
  • Las pruebas son una herramienta más, no son el objetivo.

Ejemplo de trabajo de QDev

Para poder entender mejor el concepto de cómo debería trabajar o cómo debería ser un QDev, vamos a ver un ejemplo.

Imaginemos que el equipo está compuesto por un Tech Lead, un Product owner y varios desarrolladores, entre ellos backenders, frontenders y un QDev (o más).

Desde el comienzo todos deberían participar en la definición del producto y en su arquitectura. El QDev en este punto debería comenzar a definir la estrategia de calidad:

  • Pensar en las necesidades de la QSN. La idea principal es que el equipo trabaje sobre una QSN existente u operativa.
  • Empezar a definir a alto nivel la arquitectura del SUT (system under test).

Supongamos que de ese trabajo, el QDev ha diseñado la siguiente estrategia que apoya su idea del QSN. Lógicamente esto es solo un ejemplo, muy discutible y dependiente del contexto del producto o proyecto.

De esta estrategia lo importante es entender que el QDev va a trabajar desde el comienzo del producto. Trabajará sobre las diferentes técnicas de testing que haya definido en las diferentes fases.

Siguiendo esta estrategia, el QDev no solo deberá centrarse en diseñar las pruebas e integrar las diferentes técnicas de testing, si no que, necesitará desarrollar el SUT aislado (mocks, contenedores etc) para que el equipo ejecute las pruebas de forma aislada. Incluso desarrollará herramientas para facilitar el trabajo del equipo.

Otro punto importante es no olvidarse de la importancia de seguir con el testing en la fase de producción.

Conclusiones

El evolucionar el rol de QA a QDev y comenzar a hacer uso del modelo “Prevention & Reaction” (al menos una pincelada) en nuestro caso fue un caso de éxito, pero todo depende del contexto del producto y de la madurez del equipo.

En mi caso fue muy importante la cultura del equipo y cómo entendíamos la calidad como una responsabilidad de todos. Es más, había tareas de QA que estaban diluidas en el equipo, yo entendía perfectamente que ellos harían pruebas funcionales, ya me encargaría yo de hacer el code review. Algo muy interesante es que también hacíamos pair testing.

Lo más importante es entender que el QDev, es el encargado de la QSN del producto o del proyecto. Para ello deberá tener los conocimientos suficientes para desarrollar y aplicar la estrategia de calidad, así como el SUT.

Ser el encargado no significa que sea el único responsable, como he comentado, la responsabilidad debe ser compartida por todo el equipo, por lo que es muy importante que todos participen en aplicarla.

El éxito depende de la unión del equipo, no del éxito de cada individuo.

Probe testing, the pathfinder

Introduction

A few days ago I was talking with a co-worker about a problem that his team is having.

The case is, this team consumes some APIs which contracts are changed without notifying the team and without any backward compatibility so, in the worst case, they get to the situation of having errors in production.

In an ideal world, the problem would be solved by applying contract testing or the API provider notifying about the changes, and developing always with backward compatibility, but what can we do when this is not happening?

Probe testing

We talked about the concept of using tests in the form of a probe or a pathfinder, in such a way that the tests inform us of any change in the API. In this case, I could think of several ways to probe:

Keep a scheduled test’s run, in such a way that when tests fail, we know that the contract has changed. The problem is that, as it is scheduled until it is executed and the probe detects the change, the problem could already be in production.

probe01

Keep the tests active, that is, have them running continuously. The problem that I see is that we would have a very extensive report and we could lose the real visibility of the status of the probe target. If for example, we add notifications, which would be the most logical thing to do, having a communication failure with the API we may start receiving false positive notifications. We would also have to handle the notifications.

probe02Have a listener. Imagine that changes are made in the repository of the API that we consume, if we have a service listening to this and we see or we are notified of a change, the probe will be launched to check the changes. Logically we should have view access to the repository, which is the case here, as it is part of the same company, or being a public repository.

probe03

The tests should be minimal and as simple as possible, focused on the problem, trying to avoid false positives. As a probe, we should not waste much time or resources in the maintenance. It would also be interesting to manage the probes through a dashboard: to see results, activate or deactivate them, etc.

Another interesting idea is that if we have the knowledge and resources enough, we can develop more intelligent probes, which manage their notifications system, execute, etc.

Mountebank y sus impostores, aislando nuestras pruebas

Introducción

En el blog hemos hablado en varias ocasiones sobre cómo mockear las APIs, teniendo en cuenta que es una parte importante para aislar nuestras pruebas en las arquitecturas basadas en microservicios.

Si bien es cierto que haciendo uso de contract testing podemos aislar nuestras pruebas y comprobar el correcto funcionamiento de nuestros servicios y los clientes, en ocasiones podemos necesitar llegar más lejos.

Pongamos un caso real. Hace unos meses que con mi equipo trabajamos en un proyecto en el que era necesario comunicarse con un sistema tercero asíncrono.

A nivel de pruebas lógicamente no podíamos acoplarnos a ese servicio, por lo que decidimos simularlo de alguna forma (teniendo en cuenta las restricciones tecnológicas que teníamos), es más, otros equipos necesitaban de ese servicio para sus pruebas (negocio, financiero, performance).

Por este motivo nos decantamos por desarrollar un servicio interno que simulara la respuesta del servicio externo, de tal forma que todos los equipos involucrados en el proyecto podrían utilizarlo. Con contract testing, este caso no podría ser.

Y aquí, es donde entran los “test doubles” y mountebank, una herramienta que nos va a permitir generar test doubles multi-protocolo. Gracias a Alvaro Salazar que me recomendó darle un vistazo.

¿Qué son los test doubles?

De forma sencilla, podemos decir que un test double es una copia o imagen de la respuesta y el comportamiento de un servicio.

En el caso de mountebank disponemos de dos tipos de test doubles: mocks y stubs. Dependiendo del tipo de pruebas que queramos hacer usaremos uno, otro, o los dos.

Con los mocks podemos comprobar que la llamada se ha hecho confiando en la respuesta del servidor, mientras que los Stubs, en base a una request nos devolverán una response, es decir, definimos su contrato.

¿Cómo funciona Mountebank?

Al contrario de otras herramientas, uno de los puntos fuertes de mountebank es la sencillez de generar los test doubles.

mountebank

Mountebank levanta un servicio que se encuentra a la escucha de que el cliente le mande el contrato para crear el test double, o impostor como también lo llaman. Este creará el impostor con los datos de configuración que se detallan en el contrato (protocolo, endpoint, puerto, petición, respuesta, comportamiento etc.)

La aplicación ya podrá consumir del test double, en vez del servicio real en el tiempo de test, aislando así nuestras pruebas.

Una buena estrategia es, tal como dicen en la página de mountebank, que en la preparación del entorno de pruebas, las pruebas sean las encargadas de enviar los contratos a mountebank para generar los test doubles, y cuando finalicen, sean las encargadas de comunicar que se eliminen. De esta forma todo quedará en tiempo de pruebas.

Otra forma de generar los test doubles, es mediante el uso del proxy que nos provee el servicio de mountebank. Mediante el proxy, mountebank capturará las llamadas reales que se hacen al servicio externo y creará los stubs en base a las peticiones y las respuestas que ha capturado. Lo veremos más adelante en otro post.

Un ejemplo sencillo de aislamiento

En este caso he preparado un proyecto muy muy sencillo, que podreis ver en github. En el proyecto vamos a probar la clase BookGateway, que es la encargada de consumir un servicio externo.

En este punto vemos que si nuestra intención es aislar nuestras pruebas de integración, vamos a tener que hacer un stub de ese servicio. Teniendo en cuenta que disponemos de la información, vamos a desarrollar el contrato:  

La idea es que el stub se gestione en el tiempo de pruebas, es decir, que cuando se lancen las pruebas se genere el stub, y cuando se terminen, se destruya. Para ello, vamos a  hacer uso de un cliente java de mountebank, javabank:

En el test, en el método @beforeAll vamos a crear el impostor cargandolo desde el fichero de configuración para que cada vez que se ejecute cree el impostor del servicio de book.

En el método @afterAll eliminamos todos los impostores, de tal forma que el entorno quede limpio para las siguientes ejecuciones.

El test es muy sencillo, simplemente llamamos al método getBook del gateway, el cual hará la petición al impostor en vez de al servicio externo.

Ahora solo nos queda instalar el servicio de mountebank y levantarlo, lo podéis ver en el siguiente enlace, y ejecutar las pruebas.

console

test results

El ejemplo que os he presentado es muy sencillo, con una configuración muy básica, pero mountebank nos permite generar stubs y mocks mucho más complejos, con diferentes requests y responses, así como definir diferentes comportamientos. En su documentación podéis verlo con mucha más profundidad.

Conclusiones

El disponer de test doubles (ya sea con mountebank u otra herramienta) puede ser un arma muy interesante en la batalla del testing de microservicios.

En mi opinión es una utilidad complementaria a contract testing y al uso de por ejemplo testcontainer como estrategia para llegar a tener unas pruebas determinísticas.

Uno de los beneficios de utilizar un servicio de test doubles, es que podemos utilizarlos por más de una aplicación y por más de un objetivo. Podemos tener el servicio de mountebank levantado y que diferentes pruebas consuman sus stubs. Bien es cierto que esto no es muy recomendable ya que perdemos ciertos beneficios del aislamiento ya que los compartimos, pero dependiendo del caso, tendremos la opción.

El beneficio claro de Mountebank es que es multiprotocolo, por lo que no solo nos va a proveer stubs o mocks HTTP, si no que, en el caso de querer mockear un servicio de correo SMTP o un servicio TCP también podremos. En nuestro caso hemos utilizado el cliente java, pero aquí tenéis los diferentes clientes para otros lenguajes.

Todavía me queda por investigar, es más, creo que es una herramienta que en el caso de mi equipo puede sernos de utilidad, así que os iré informando!