¿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.

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.

Intelligent testing, ¿Llega una nueva era?

Introducción

A través de un tweet de Lisa Crispin, llegue a un artículo del blog de Mabl, en el que hablaban un poco sobre el concepto de “intelligent testing”.


En este artículo me gustaría repasar los cuatro principios que se tratan del Intelligent testing. Si bien es cierto que el video del blog habla sobre cómo lo aplican a través de Mabl, intentaré ser agnóstico al producto.

¿Qué intenta resolver “Intelligent testing”?

Para entender el concepto de intelligent testing, creo que es necesario conocer los “defectos” del testing convencional (vamos a llamarlo así).

En mi opinión el testing convencional estaba pensado y muy acoplado a las metodologías de desarrollo convencionales. Con la entrada de las metodologías ágiles, el testing ha sufrido ciertos cambios intentando adaptarse, pero no siempre con el éxito que debería.

Esto ha provocado que el testing llegue a ser el cuello de botella del sistema de CI/CD. Para evitarlo y poder implementar el testing dentro de las metodologías ágiles, en muchas ocasiones se ha tenido que crear estrategias de testing muy acopladas al sistema de CI/CD, lo que tampoco es del todo correcto.

Creo que la evolución del testing siempre ha estado por detrás del desarrollo, cuando debería ir de la mano. También creo que gran parte de la culpa la tenemos los testers y QA/QEs que nos hemos ido adaptando al código y a la tecnología, en vez de estar a la altura. Debemos ser más preventivos y menos reactivos. Todavía nos queda mucho por aprender.

Lo que intenta el “testing inteligente” es básicamente eso, dejar que el testing sea el cuello de botella de nuestro desarrollo, y para eso se basa en cuatro principios.

1.º principio: Adaptarse a los cambios

Uno de los grandes problemas de la automatización, son los falsos positivos. Cuando lanzamos la suite de pruebas podemos encontrarnos con una gran número de fallos que tendremos que analizar, ya que seguramente un porcentaje de los fallos sea debido a falsos positivos.

Algunos falsos positivos vienen dados por cambios en el código que hacen que nuestro test falle, sin que en realidad sea un fallo de la aplicación. Esto suele ocurrir mucho en el caso de las pruebas de UI.

En las pruebas UI, nuestro test está acoplado a los componentes con los que interactúa, lo que hace que el test sea altamente sensible. Cuando por alguna razón el xpath o el selector del componente cambia, nuestro test falla. No quiere decir que sea error de la aplicación, es un caso de falso positivo.

Tenemos que adaptar manualmente el test y volverlo a lanzar. Esto supone una inversión de tiempo alto, por lo que somos un cuello de botella.

Lo ideal sería que el framework de testing sea lo suficientemente inteligente como para identificar el problema (un cambio del selector, en el caso anterior), identificar el cambio, probarlo y hacer los cambios en el test, de las forma que las siguientes ejecuciones vayan correctamente.

Claro, esto es relativamente “fácil” en las pruebas de UI. Pero qué ocurre si realizamos otro tipo de pruebas funcionales o de performance (porque recordemos que podemos integrar las pruebas de performance dentro de nuestro CI).

En estos casos no lo veo tan claro que sea tan fácil de adaptar el test. Supongamos que realizamos pruebas funcionales de API, lanzamos las pruebas y fallan debido a un cambio de contrato. Entiendo que si tenemos los contratos definidos y actualizados o hacemos uso de contract testing, podremos adaptar nuestros tests basados en esas fuentes de conocimiento.  

En el caso de las pruebas de rendimiento, debería depender de qué tipo de pruebas o sobre que se lancen (UI, API etc.), y adaptarse.

Otra opción que se me ocurre sería disponer de un sistema inteligente que “analice” los cambios y notifique o haga los cambios pertinentes en las suites de testing, sea del tipo que sea, funcionales, performance…

2.º principio: Testing desde el Cloud

 

Otra forma de reducir el tiempo de ejecución de las pruebas es la ejecución en paralelo. Las plataformas Cloud nos facilitan este hecho, ya que podremos disponer bajo demanda o escalar el número de ejecuciones y entornos sobre los que queremos lanzar las pruebas.

En el caso de las pruebas funcionales podremos reducir considerablemente el tiempo de ejecución, debido a que dividiremos las pruebas por el número de “ejecutores”.

En el caso de las pruebas de rendimiento podremos aumentar la carga o el número de usuarios virtuales sin penalizar el gestor de carga.Al lanzarlo sobre sistemas cloud podremos beneficiarnos de los servicios de estas plataformas, como sistemas de análisis (para analizar los resultados), heurísticos etc..

Cloud testing

 

3.º principio: El output debería ser más afirmativo y resolutivo

Como he comentado en el primer principio, tras terminar las pruebas, hay una fase de análisis de resultados. En muchas ocasiones (por no decir en la gran mayoría), cuando hay fallos, los resultados no son del todo claros y nos toca invertir tiempo en ver cual es el problema.

Esta inversión de tiempo, una vez más, nos lleva a ser un cuello de botella para los resultados, y en otras ocasiones a que se nos escapen bugs, debido a la falta de atención que ponemos en su resolución.

El que las pruebas den un output con la información necesaria (ni exceso, ni defecto) y esa información llegue a ser resolutiva, es tan importante como unos buenos teses. De nada sirve tener un test perfecto, si los resultados no son lo suficientemente informativos.

Hoy en día sacamos trazas (en ocasiones excesivas) y screenshots (en ocasiones confusos), pero no es suficiente para reducir el tiempo de análisis de los resultados.

Bajo mi punto de vista, tenemos que invertir muchos más esfuerzos en mejorar este punto. La parte buena es que los sistemas heurísticos y de machine learning cada vez están más avanzados, y creo que de alguna forma podremos integrarlo con el testing.

Creo que sería interesante disponer de un output inteligente, donde en base a los resultados obtenidos, comparándolo con una fuente de conocimientos de otros resultados anteriores y los cambios realizados, podamos dar unos resultados, no solo con buena información, si no, con el problema detectado y parte de su resolución.

4.º principio: Testing integrado en el CI

Este último principio creo que es el que está más integrado. Actualmente hay pocas empresas que no tengan el testing integrado en el sistema de CI/CD. Ya son muchos sistema de CI que disponen de plugins para muchos frameworks de testing.

El problema es que si no se cumplen los otros tres principios, el testing seguirá siendo el palo en la rueda del CI.

Conclusiones

El testing inteligente es un muy buen concepto que acerca cada vez más la posibilidad de estar a la altura de la evolución del desarrollo, creo que todavía queda por evolucionar varios aspectos, pero es factible, lo que es muy buena noticia.

Parte de esa responsabilidad recae en los testers y QA/QEs que creo que necesitamos una evolución como concepto y rol. No podemos seguir anclados en el probar el software, ni en la idea idílica de “garantizar la calidad”.

La tecnología de hoy en día, el cloud, la heurística, nos permite dar un paso más adelante y ayudarnos a anteponerse a los errores, más que encontrarlos.

Aislando nuestras pruebas con Testcontainer

Introducción

Hace unos días escribí sobre las pruebas aisladas e integradas. Uno de los mayores retos en nuestra estrategia de testing es el hecho de intentar aislar nuestras pruebas.

Hemos visto cómo aislarlas mediante contract testing, pero; ¿Cómo aislamos nuestras pruebas de integración o las funcionales?

En este post vamos a hablar sobre Testcontainer, una librería de java que nos provee instancias ligeras de cualquier contenedor de Docker (bases de datos, navegadores, servicios etc.).

Como siempre vamos a ver los ejemplos con un proyecto que podréis descargar desde GitHub.

Vamos a ello!

Aislando las pruebas del proyecto

App architecture
El proyecto de ejemplo es sencillamente una aplicación conectada a una base de datos MySQL y que consume a encoder-service,  un servicio propio, que es usado por todas nuestras aplicaciones.

Vamos a desarrollar pruebas de integración. Comprobaremos que nuestra aplicación comunica correctamente tanto con la base de datos, como con el servicio.

Mediante Testcontainer cuando ejecutemos las pruebas, se levantará un contenedor Docker de MySQL y otro de encoder-service.

Una de las preguntas que os podéis hacer, es el porqué levantar un contenedor del servicio, si lo podemos mockear. Hay ocasiones en las que cuando realizamos pruebas, necesitamos recibir un comportamiento real, y no uno esperado. Este ejemplo pretende acercarse a esa realidad.

Test architecture

Añadiendo Testcontainer al proyecto

Vamos a añadir dos dependencias a nuestro proyecto. Las dependencias generales de Testcontainer, y la dependendencia de testcontainer de MySQL.

Además de añadir las dependencias de Testcontainer, deberemos tener las dependencias del conector de MySQL y Spring data.

Pruebas de integración sobre MySQL Testcontainer

Lo bueno de utilizar Spring Data JPA,  es que nos facilita la implementación y por tanto el uso de la capa de datos. Testcontainer se adapta muy bien a Spring Data JPA debido a que nos provee un driver jdbc que gestiona el contenedor de base datos.

Lo que nos interesa es ejecutar el contenedor de MySQL en tiempo de test, por lo que la configuración la vamos a añadir en el directorio test.

En la configuración de JPA, es importante destacar la propiedad de ddl-auto. El valor que vamos a indicarle es create-drop, de esta forma cuando se instancie el contenedor, se creará la base de datos con nuestra entidades.

Para las pruebas vamos a añadir unos datos iniciales a la base de datos, por lo que cuando se creen las tablas, se ejecutará el fichero data.sql. Para ello es importante que la propiedad initialization-mode tenga el valor always, en la configuración de datasource.

Lo más importante es driverClassName, donde indicaremos el driver de Testcontainer. En la propiedad de la url de conexión, el hostname, el puerto y el nombre de la base de datos van a ser ignorados.

El test que es muy sencillo, únicamente comprueba que se almacena y se leen los datos de la base de datos. Lo importante es sacar la conclusión de que el uso de testcontainer es totalmente transparente para el test, es decir, el test no sabe que está ejecutando las pruebas contra un contenedor de MySQL. Por lo que sí tenemos la necesidad de cambiar de base de datos o de versión de la base de datos, nuestras pruebas no se van a ver afectadas.

testcontainer results

 

Pruebas de integración sobre enconder-service Testcontainer

Primero, hemos tenido que “dockerizar” el encoder-service y añadirlo a nuestro local registry. Ahora en la configuración test de nuestra aplicación vamos a añadir el fichero docker-compose, con la configuración mínima para instanciar el contenedor de nuestro servicio.

En este caso, nuestro test si va a estar acoplado a las dependencias de Testcontainer, debido a que tenemos que hacer uso de docker compose.

Como hemos comentado, dado que queremos instanciar el contenedor de nuestro servicio desde el fichero de docker-compose.yml, vamos hacer uso de DockerComposeContainer, indicando el nombre del servicio y el puerto. En el test, obtenemos la url y el puerto del contenedor mediante getServiceHost y getServicePort. Realmente es muy sencillo.

testcontainer result encoder service

Conclusiones

Testcontainer nos permite aislar nuestras pruebas de forma muy sencilla. Mediante Spring data JPA y Testcontainer nuestras pruebas de integración de base de datos estarán totalmente desacopladas.

La mayor pega puede ser el hecho de que si queremos hacer uso de Docker compose, nuestras pruebas no van a disfrutar de la virtud de estar desacopladas de Testcontainer.

Al aislar las pruebas reducimos el tiempo de prueba, debido a que no necesitamos hacer conexiones reales y reducimos el número de falsos positivos por fallos en el otro extremo.

El sistema de CI/CD se puede ver muy beneficiado, dado que no vamos a necesitar desplegar todos estos servicios, BBDD etc. en nuestro entorno, por lo menos en entornos previos al stage o preproducción, y los desarrolladores podrán probar con mayor fiabilidad su código.

Además, Testcontainer nos proporciona librerías para hacer pruebas de UI, por ejemplo con Selenium. Y bueno… como habéis visto en el caso de encoder-service, cualquier aplicación dockerizada se podrá instanciar con testcontainer.

¿Un QA puede ser también developer?

Assert QA == Developer


¿Es un QA un developer?
Me gusta hablar con la gente. Me gusta compartir opiniones. Me gusta debatir. Tras varias conversaciones con compañeros de trabajo, de los que he podido obtener de una forma u otra feedback de lo que creen que es el trabajo de un QA Engineer, me he propuesto a escribir un post que ayude a romper ciertas barreras mentales en el trabajo que creemos que hace un ingeniero de calidad y ver si en realidad es un developer.

Ingeniería de la calidad del software

La realidad es que poca gente conoce lo que es la ingeniería de la calidad. No es algo conocido, no es algo que llame la atención cuando decides estudiar informática, es la realidad.

Cuando un desarrollador habla de un QA, no piensa que desarrolle, no lo trata como un desarrollador. Es más, muchos piensan que los QAs son desarrolladores frustrados, y no es cierto.

¿Porque cuesta tanto ver la ingeniería QA como una rama de la ingeniería del software, del desarrollo?

Cuando se piensa únicamente desarrollamos pruebas se está muy equivocado. La calidad del software no solo se garantiza con teses.

Desarrollamos teses, ¡por supuesto que sí! Y en muchas ocasiones la lógica que implementamos en el test puede ser más compleja que el código o la funcionabilidad que probamos. Y si… sabemos lo que son los patrones… es más, los aplicamos.

Para garantizar que el software cumple con los requisitos de calidad exigidos los QAs deben diseñar y aplicar las estrategias de calidad necesarias. Y muy seguramente en esas estrategias se implementen diferentes proyectos, desde automatización de pruebas hasta proyectos más complejos, y adivinad, muchos de ellos habrá que desarrollarlos.

Automatización de pruebas

Automatizar pruebas funcionales no siempre significa automatizar el comportamiento de una funcionalidad mediante UI testing. En muchas ocasiones se requiere hacer pruebas funcionales a nivel de API, o probar funcionalidades cross-aplicación y cross-dispotivo.

Aquí os dejo los enlaces a la presentación y explicación de cómo Uber realiza pruebas cross-aplicación y cross-dispotivo para probar sus aplicaciones mediante Octopus.

POST:
https://eng.uber.com/rescued-by-octopus/
SLIDE:
https://docs.google.com/presentation/d/1vYXhkvgLKun72Ix91LQDDWZQdcY5VOBqKVvI1Y6riYo/pub?slide=id.gd8d657045_0_0

VIDEO:
https://www.youtube.com/watch?v=p6gsssppeT0

Para mi es importante entender que un QA no es una persona dedicada únicamente a automatizar pruebas o a realizar testing. Es un ingeniero capaz de desarrollar las herramientas necesarias que ayuden a garantizar la calidad de la aplicación.

Lo que significa que un QA es un desarrollador especializado en la calidad.

Sí, somos un equipo

Una de las cosas que me dijeron era que si el que desarrollaba la tarea hacia bien su trabajo no tenía por qué meter bugs, y ya que sabía lo que estaba desarrollando y donde afectaba él podría hacer las pruebas, por lo tanto, los QAs sobraban.

Bueno, en un mundo perfecto donde el desarrollador está encantado de probar todo lo que hace, y donde el tiempo de entrega no existe, en el que nunca se equivoca, puede ser…¡pues tampoco! Que te diga coca cola o Samsung que no hacen control de calidad de sus productos… igual sus móviles explotarían.

Es necesario desarrollar estrategias y proyectos que garanticen la calidad de nuestras aplicaciones, equipar al equipo de desarrollo con las herramientas suficientes para hacer código de calidad, para agilizar su desarrollo.

Cada equipo somos piezas del desarrollo. Desarrollo, DevOps, Producto, QA etc.

Conclusiones

Antes de ser QA fuí desarrollador, y hoy en día sigo desarrollando casi al mismo nivel que antes, salvo que antes funcionalidades de una aplicación, y ahora herramientas que garantizan su calidad. ¿Qué diferencia hay?

Los QAs también somos desarrolladores, es la realidad, y primero nos lo tenemos que creer nosotros para que los demás se lo crean.

 

 

 

 

Estrategia Prevention & Reaction – Parte III

Introducción

En el segundo capitulo vimos cómo aplicábamos la estrategia Prevention & Reaction en tiempo de producción. En el último post de la serie, vamos a ver un ejemplo de organización de equipos QA que garantizan la estrategia en todas sus fases y contextos.

Equipos de trabajo

stategy teams

Para poder garantizar la calidad del software siguiendo la estrategia se crea una estructura grupal en la que cada grupo de trabajo se dedica o toma la responsabilidad de áreas concretas de la calidad del software.

La importancia de la estructura grupal planteada reside en la necesidad de cohesión de los grupos de trabajo, debido a que las tareas realizadas por un equipo son necesarias para otro.

Esto genera la posibilidad de disponer de personas multidisciplinares, es decir, personas que puedan participar en distintos grupo de trabajo a la vez, o permitir la rotación grupal.

La imagen muestra la cohesión de la que estamos hablando, así como la cobertura de cada grupo.

De forma general, se puede apreciar que el grupo strategy  abarca los demás grupos, debido a que sus decisiones afectan a todos los grupos.

Otro ejemplo es el equipo de Testing, el cual abarca las células de desarrollo dado que tiene que dar servicio y soporte de testing.

Vamos a ver la responsabilidad de cada grupo.

Equipo de estrategia

De forma general, el equipo de estrategia debe procurar mantener la estrategia y tomar decisiones importantes sobre la misma, debiendo corregir el rumbo cuando no se siga el camino previsto.

Las responsabilidades más importantes son:

  1. Diseñar la estrategia: Este equipo debe tener siempre presentes las necesidades en cuanto a la calidad del software se refiere y desarrollar una estrategia de calidad que las cubra.
  2. Definir KPIs: Los KPIs servirán para ver si la estrategia sigue el buen camino. En el caso de que los KPIs nos muestren indicios de que no se cumplen los objetivos preestablecidos, se podrán tomar decisiones con antelación para así poder pivotar la estrategia.
  3. Integrar la calidad en el CI: Hemos visto en las diferentes fases que la estrategia requiere estar presente en el flujo de la integración continua; es, precisamente, el equipo de estrategia el que deberá garantizarlo.

Equipo de datos

Durante el análisis que hemos hecho de la estrategia, hemos recalcado la importancia de obtener los datos de los resultados de las pruebas, de los datos de producción y de disponer de un sistema de predicción de bugs.

Las responsabilidades más importantes son:

  1. Obtención de datos de pruebas: Se deberán desarrollar las herramientas necesarias para obtener los datos de los resultados de las pruebas. Como hemos ido diciendo durante la serie de posts, los datos obtenidos nos servirán para alimentar la heurística del sistema de predicción de bugs, así como para mantener un histórico de resultados.
  2. Obtención de datos de producción: Los datos de producción van a servirnos para disponer de datos objetivos que nos ayuden a crear un mapa de calor de acciones, o bien como datos de entrada para las pruebas. Si nos fijamos en los logs de producción, podremos localizar trazas de errores y adelantarnos a solucionarlos o a reportarlos.
  3. Obtención de datos para KPIs: Los KPIs son indicadores o métricas que nos aportan conocimiento del estado de las acciones que estamos realizando. Mediante los KPIs seremos capaces de detectar defectos en nuestra estrategia o, por el contrario, ver el éxito de la misma. El equipo de datos debe desarrollar las herramientas necesarias para poder obtenerlos.
  4. Análisis y reporte de los datos: El análisis de los datos es de las acciones más importantes que debe realizar el equipo, dado que los resultados de los análisis son decisivos para la estrategia.

El equipo de datos tiene que trabajar estrechamente con los demás equipos de QA, debido a que va a necesitar extraer datos de todas las pruebas, así como de los resultados de la validación de las RCs o de la gestión de bugs. Estos datos serán analizados junto con el equipo de estrategia.

Equipo de automatización

El equipo de automatización deberá desarrollar los proyectos o herramientas necesarias para la ejecución de las pruebas automáticas. Los proyectos no tienen por qué ser únicamente desarrollo de pruebas automáticas; el equipo de automatización también se encargará de desarrollar los frameworks necesarios para el desarrollo de las mismas.

Las responsabilidades más importantes son:

  1. Framework de desarrollo de pruebas: Para muchos casos es necesario desarrollar, adaptar o mejorar un framework de testing. El equipo de automatización tiene que proveer ese framework a los equipos que desarrollen pruebas automáticas, ya sean ellos mismos o los desarrolladores.
  2. Desarrollo de pruebas funcionales: A pesar de que los desarrolladores implementen pruebas funcionales de sus tareas, es posible que el equipo de automatización necesite realizar unas pruebas automáticas de más alto nivel. Dentro de estas pruebas, se pueden listar también pruebas E2E, API, Mobile etc.

Es necesario que el equipo de automatización trabaje estrechamente con los departamentos de producto y de desarrollo, debido a que las pruebas que se desarrollen van a depender mucho de las conversaciones entre los diferentes departamentos.

Equipo de Rendimiento y Seguridad

El rendimiento y la seguridad de nuestra aplicación son unos de los valores más importantes que tenemos que garantizar, pero no siempre son los más sencillos. El equipo de rendimiento y seguridad se deberá encargar de desarrollar las pruebas necesarias que garanticen la calidad de ambos aspectos.

Las responsabilidades más importantes son:

  1. Pruebas de rendimiento: Disponer de una suite de pruebas de rendimiento (pruebas de carga, estrés, estabilidad, etc.).
  2. Pruebas de seguridad: A pesar de que los desarrolladores implementen pruebas funcionales de sus tareas, el equipo de automatización es posible que necesite realizar unas pruebas automáticas de más alto nivel. Dentro de estas pruebas, se pueden listar también pruebas E2E, API, Mobile etc.

El equipo de rendimiento y seguridad debe trabajar estrechamente con el departamento de sistemas o sysop, debido a que sus pruebas van a tener impacto en los entornos y en la aplicación.

Equipo de Testing

Dentro de las tareas más importantes se encuentra el validar o rechazar la RC y para ello es necesario que el equipo de testing realice las pruebas correspondientes. Por otro lado, el tratamiento de bugs y las pruebas bajo demanda también son tareas del equipo de testing.

Las responsabilidades más importantes son:

  1. Validación de RCs: Sacar la RC adelante es la finalidad de todos (desarrolladores, sys, QA, producto etc.), por lo que es la tarea más importante del equipo de testing. En caso de que en tiempo de RC en la fase de prevención todo haya ido bien, en fase de reacción los testers deberán buscar cualquier fallo crítico y, en caso de localizarlo, rechazar la RC.
  2. Pruebas bajo demanda: En ocasiones es necesario realizar pruebas bajo demanda sobre una tarea en concreto. Se suele hacer cuando la tarea es compleja o crítica. De esta forma, nos podremos asegurar que no vamos a meter fallos en la RC.
  3. Diseño de casos de prueba: Sin casos de pruebas no se sabe qué probar. El equipo de testing deberá diseñar los casos de prueba necesarios para la validación de la RC, o para el testing bajo demanda.
  4. Tratamiento de bugs: Cuando en producción se localiza un fallo o un bug es necesario reportarlo. El equipo de testing tiene que reproducirlo y aportar la información necesaria al equipo de desarrollo para que lo solucionen. Un aspecto, en mi opinión, importante y a veces olvidado es que disponer del conocimiento suficiente para entender el código de la aplicación ayudará al tester a obtener más información del error. De este modo, el desarrollador invertirá menos tiempo en solucionarlo.

El equipo de testing tendrá que trabajar estrechamente con el equipo de producto y desarrollo para obtener la información necesaria que permita preparar los casos de prueba frente a posibles bugs.

Conclusión final

Durante la serie de posts, hemos visto en qué se basa la estrategia de “Prevention & Reaction”. Es una estrategia teórica, basada en mi experiencia como QA, en lo que he aprendido estos años y en cómo hoy en día enfocaría el trabajo para garantizar la calidad en un entorno de desarrollo ágil.

La finalidad de la estrategia es garantizar la calidad desde una etapa temprana. Su base principal son los datos y el análisis de los mismos, pero también puede ser su punto débil, debido a que al comienzo de la implementación de la estrategia no disponemos de los datos suficientes. No obstante, como suele ocurrir, su punto débil también es su punto fuerte.

A medida que dispongamos de más datos, la heurística de nuestro sistema de predicción de bugs será mejor y, por lo tanto, nos ayudará a reducir el riesgo de dejar pasar fallos a producción.