Predicción de bugs, mito o realidad!

Introducción

Desde hace tiempo me produce bastante curiosidad el hecho de que puedan existir sistemas o algoritmos que nos puedan ayudar a “predecir” la existencia de bugs en nuestro software. Así leído puede parecer idílico e incluso algo difícil de creer dado que de base ya podemos pensar que hay muchos factores que pueden afectar a la inserción de un bug en nuestro código.

Para la predicción de bugs necesitaríamos una cantidad de datos importantes respecto al código, cambios realizados en la release, histórico de bugs. Y con todo ese caldo de datos…pum… magia?

Para que veáis que no solo puede afectar la parte técnica como curiosidad os dejo este enlace a un post que sobre todo es curioso.

Así que me he puesto a investigar un poco y ver la realidad y sobre todo los beneficios que nos puede aportar.

Algoritmo de predicción de bugs – FixCache

Existen varios algoritmos en lo que a la predicción de bugs respecta pero en este artículo me gustaría centrarme en el algoritmo FixCache y realizar una comparativa en artículos posteriores.

Actualmente existen dos tipos de estrategias para la predicción de bugs:

  1. Basados en las métricas de calidad como lineas de código (LOC) y la complejidad ciclomática.
  2. Basados en el control de cambios e histórico del repositorio.
fixcache_ratevstime
Imagen 1: Hit rate vs time for projects

FixCache entraría en el segundo grupo, dado que se sirve del repositorio de código para analizar los cambios y así predecir los posibles bugs.

En la imagen 1 vemos un ejemplo de la tasa de éxito del algoritmo FixCache sobre cuatro aplicaciones diferentes.

El algoritmo trabaja observando los cambios realizados en los ficheros o los métodos y utiliza tres heurísticas para añadir los ficheros a la “caché”:

 

 

 

  • Nuevos ficheros de código o modificados los cuales pueden contener bugs.
  • Ficheros que actualmente contienen bugs son propensos a contener más bugs (Aquí entra la teoría del “defect clustering”)
  • Ficheros que han sido modificados para solucionar algún bug son propensos a contener otros bugs.

Como hemos indicado para crear la “caché” de datos se sirve del repositorio de software, donde identificará los cambios realizados en los ficheros mediante los commits  al proyecto comparándolo con su propia base de datos o caché.

La gestión del caché es importante, normalmente cacheando un 10% de los ficheros del repositorio al finalizar el periodo de análisis. Es importante determinar si la caché está completa para remover los ficheros que no vayan a formar parte de posteriores análisis, para ello se pueden implementar varias políticas de reemplazo (parecido a las de la gestión de memoria caché de nuestro sistema):

  • El fichero menos utilizado recientemente (LRU).
  • El fichero que menos cambios ha tenido .
  • El fichero que menos bugs ha tenido históricamente.
  • El fichero que menos autores de cambios tenga.

Sería interesante ver que política de reemplazo da mejores resultados, lo cierto es que la más utilizada es LRU, me imagino que por su baja complejidad de gestión respecto a los demás.

Practicidad del sistema de predicción de bugs

Ya hemos visto un ejemplo de algoritmo que se basa en los cambios en los ficheros del repositorio pero,  ¿Que utilidad podemos darle al uso de un algoritmo de predicción de bugs?

En un sistema de CI (continuous integration) donde se aplique la metodología ágil, donde se realizan cambios a diario en el código y donde la intención es realizar despliegues a producción continuamente puede ser una muy buena opción para ayudar al equipo de QA en sus pruebas. Pongamos varios ejemplos:

  • Lanzar pruebas de regresión automáticas de aquellas funcionalidades o aquellos ficheros que el algoritmo detecte con riesgo de bugs en cada RC (release candidate).
  • Crear un “semaforo” que identifique las zonas de riesgo de la RC y así focalizar las pruebas o reforzarlas para prevenir bugs.
  • Mantener un histórico de ficheros conflictivos que puede ser utilizado a modo informativo por QA, desarrolladores etc.

Conclusiones

Depende de nuestro sistema de CI y la finalidad puede que nos sea más o menos viable implantar un sistema de predicción de bugs, lo cierto es que no muchas empresas disponen de ello (que se sepa) y puede ser interesante únicamente en los casos que se realicen cambios en nuestro código continuamente.

Bibliografía

  1. https://users.soe.ucsc.edu/~ejw/dissertations/AdaptiveBugPrediction_SungKim_Thesis.pdf
  2. http://static.googleusercontent.com/media/research.google.com/es//pubs/archive/41145.pdf
  3. http://www.mysmu.edu/faculty/davidlo/papers/csmr13-reopened.pdf
  4. https://users.soe.ucsc.edu/~supertri/docs/msr2011-final.pdf
  5. http://www.softwaretestingclub.com/profiles/blogs/defect-clustering-pesticide-paradox
  6. http://www.malavida.com/es/noticias/control-biometrico-para-predecir-errores-de-codigo-en-programacion-006101

Y que me dices de “Agile Testing Quadrants” – Parte III

Introducción a “Agile Testing Quadrants”

En los anteriores post de la serie hemos dado una pequeña introducción de lo que son los cuadrantes del testing  y las pruebas que realizamos en el primer cuadrante en “Y que me dices de “Agile Testing Quadrants” – Parte I” .

La importancia del segundo cuadrante y sus pruebas las tratamos en el post Y que me dices de “Agile Testing Quadrants” – Parte II” .

En este artículo vamos a hablar sobre el tercer cuadrante de los !Agile Testing Quadrants.

Agile Testing Quadrants

Tercer cuadrante – Q3

Para el cliente no solo es importante que el software funcione, el cliente espera que la aplicación funcione como tiene que funcionar en todos sus aspectos, es decir, que se cumplan todas sus necesidades y las “features” que se ofertan.

El tercer cuadrante de los “Agile Testing Quadrants” se preocupa de probar que el producto es el deseado, que la aplicación dispone de las funcionalidades que se han definido y que estás son correctas. En ocasiones nos encontramos con que se desarrolla una nueva funcionalidad que no es lo que espera el cliente, esto puede ser debido a que no se ha entendido bien los requerimientos, no se ha realizado un buen análisis o faltan casos por contemplar.

La clave de las pruebas del tercer cuadrante es ponernos en la piel del cliente, ya que vamos a intentar garantizar que se cumplen sus necesidades y que las funcionalidades son correctas.

En este tipo de pruebas emularemos el comportamiento del usuario mediante pruebas manuales. Realizar pruebas manuales requiere de ciertas habilidades por parte del tester:

  • Organización: Antes de realizar las pruebas es necesario organizar correctamente tanto las rutas de test para garantizar una buena cobertura como disponer de los datos necesarios para realizarlo.
  • Curiosidad: Durante el transcurso de las pruebas no puede faltar la curiosidad dado que vamos a tener que probar funcionalidades que probablemente no hayamos probado anteriormente.
  • Intuición: En muchos casos se detectan fallos o errores debido a que anteriormente nos hemos peleado con un escenario similar en el que hemos encontrado algún fallo. Este conocimiento nos dará cierta intuición en las pruebas.
  • Empatía: En muchos casos tenemos que ponernos en la piel del usuario para realizar ciertas pruebas. El usuario no siempre hace uso de las funcionalidades correctamente o no las utilizan como o para lo que se hicieron.

Me gustaría centrarme un poco más en el “Exploratory testing” pilar del tercer cuadrante. Este tipo de pruebas requiere de cada una de las habilidades que hemos hablado anteriormente. Durante la sesión el tester diseñará y ejecutará las pruebas analizando los resultados. La clave de este tipo de pruebas es que nos ayudará a aprender y a obtener mayor conocimiento de la aplicación que se está probando y lo más importante, a encontrar la mayoría de los bugs.

Como en los posts anteriores os hablaré de mi experiencia. Donde trabajo actualmente las aplicaciones que tenemos tienen muchos casos de prueba, muchas funcionalidades que aportan una mayor complejidad y mayor reto a los QAs. Normalmente me dedico a probar las RCs, a desarrollar pruebas automáticas y  a comprobar los bugs que se publican, pero cuando saco un rato libre me dedico a realizar “Exploratory testing” donde encuentro la mayor parte de los bugs, cierto es que son bugs antiguos que no han entrado con las nuevas funcionalidades. El realizar este tipo de pruebas me ha hecho aprender de la aplicación y a plantear dudas que se han podido traducir en conocimiento, bugs o en casos que no se han contemplado para dicha funcionalidad.

Conclusiones

 

El tercer cuadrante de los “Agile Testing Quadrants” se centra en comprobar que se cumplen las necesidades del cliente y que las funcionalidades de la aplicación son correctas. Para ello el tester tendrá que ponerse en la piel del usuario y disponer de ciertas habilidades que apoyen y den valor a las pruebas.

Uno de los pilares del tercer cuadrante es el “Exploratory testing” donde el tester durante la sesión diseñará, probara y analizará los resultados de las pruebas que va ejecutando manualmente, siendo el conocimiento aprendido de la aplicación uno de los objetivos más importantes.

Enlaces a la serie de posts

Histórico de los resultados de Geb – Parte I

Introducción

Cuando se lanzan pruebas automáticas uno de los pasos posteriores a la ejecución suele ser el análisis de los resultados. Es importante comprobar que las pruebas se han lanzado correctamente y verificar la veracidad de los resultados tanto positivos como negativos detectando falsos positivos. Es por ello que mantener un histórico de los resultados puede llegar a ser muy interesante y nos ofrece grandes ventajas:

  • Comparativa frente a resultados anteriores
  • Detección de falsos positivos en base al histórico de los mismos
  • Ver la evolución de las pruebas
  • Ver el crecimiento de cobertura

Se pueden listar un mayor numero de ventajas que se nos puedan ocurrir, pero lo más importante es que mantener un histórico nos va a proporcionar una fuente de conocimiento de las ejecuciones que podremos consultar en un futuro.

Como he escrito en el título, vamos a extraer los datos de los resultados de Geb, que nos permite realizar pruebas funcionales integrándose en nuestro caso con Spock.

Vamos a ello.

Resultados de ejecución

Al ejecutar las pruebas los resultados de la ejecución por defecto se almacenan en el directorio:

[project]/target/test-reports/

Vamos a encontrarnos con los siguientes ficheros:

TESTS-TestSuites.xml: Fichero con los resultados de la ejecución del test suite por completo

TEST-functional-spock-[Spec].xml: Ficheros con los resultados de las ejecuciones de los Spec. Uno por cada spec que esté definido.

Html: Directorio donde se encuentran los resultados en formato html

En nuestro caso vamos a extraer los datos del fichero TESTS-TestSuites.xml.

Análisis para extracción del histórico de resultados

Hemos lanzado las pruebas del proyecto que vimos en el post https://qajungle.com/restful-api-functional-testing/ . El fichero de resultados, en este caso con resultados positivos:

De estos resultados se puede ir observando que disponemos de varios datos interesantes para extraer, vamos a categorizarlos como datos informativos y mediciones.

Datos test suites

Dentro del fichero de resultados se listan los test suites que han sido ejecutados, en este caso solo uno, veamos que datos interesantes nos aportan:

testsuite errors="0" failures="0" hostname="aritzaguila.local" id="0" name="PostsAPISpec" package="" tests="1" time="0.912" timestamp="2016-06-21T09:42:17"

Datos informativos
Los datos informativos nos van a servir para identificar correctamente la prueba que se ha ejecutado.

  • Hostname: Nombre del host donde que se ha ejecutado la prueba. Puede ser interesante siempre que ejecutemos las pruebas en diferentes máquinas o en caso de que las balanceemos.
  • Name: Nombre del Spec que se ha ejecutado.
  • Timestamp: Hora la que se ha ejecutado el Spec.

Datos medibles
Los datos medibles nos van a servir para ver, medir, comparar y evaluar los resultados de las pruebas.

  • Errors: Errores de ejecución de la prueba. Normalmente suelen ser debido a excepciones de ejecución.
  • Failures: Fallos de la prueba. Normalmente suelen ser fallos los incumplimientos de las pruebas.
  • Tests: Número de tests ejecutados correctamente.
  • Time: Tiempo de ejecución del Spec, en milisegundos.

Datos test cases

Cada test suite dispondrá de los casos de prueba que se han ejecutado, en nuestro caso uno.

testcase classname="PostsAPISpec" name="check that the API returns all posts data" time="0.909"

Datos informativos

  • Classname: Nombre de la clase donde se encuentra el test case.
  • Name: Nombre del test case.

Datos medibles

  • Time: TIempo de la ejecución del test case.
  • Name: Nombre del test case, en milisegundos.

Es muy importante recalcar que en caso de que haya habido un error o un failure en el caso de prueba se añadirá una nueva etiqueta con la información del error o el failure.

Ejemplo para error:

En el caso de un failure la etiqueta sería <failure>.

Enlaces a la serie de post

  1. Creando un histórico de los resultados de Geb – Parte II

Y que me dices de “Agile Testing Quadrants” – Parte II

Introducción a “Agile Testing Quadrants”

En el post “Y que me dices de “Agile Testing Quadrants” – Parte I”  hablamos de lo que eran los cuadrantes del “testing” y dimos una pequeña introducción a las pruebas que se realizaban en el ámbito del primer cuadrante.

En este capítulo de la serie vamos a hablar de la finalidad de las pruebas del segundo cuadrante.

 

Testing Quadrants

Segundo cuadrante – Q2

Las pruebas del segundo cuadrante dan soporte al equipo de desarrollo desde un nivel más alto. Mediante las pruebas manuales y automáticas verificaremos que se cumplen los requerimientos de negocio.

Lo importante de las pruebas del segundo cuadrante es que intentaremos automatizar la mayoría de las mismas, cierto es que posiblemente haya algunas pruebas que tengamos que hacerlas manualmente debido a la complejidad de la automatización o al interés mismo de la prueba bajo el coste de automatización.

A diferencia del primer cuadrante en el segundo se realizan mayor tipo de pruebas para verificar los requerimientos de negocio:

  • Pruebas funcionales para verificar la funcionalidad de la aplicación. El mayor ejemplo lo podemos ver en las pruebas a nivel GUI, que validan las funcionalidades de la aplicación desde la capa visual. Se desarrollan con frameworks que ayudan a automatizar las acciones en el navegador, como por ejemplo selenium.Pero las pruebas funcionales no solo se realizan a nivel GUI, también se realizan otro tipo de pruebas funcionales como por ejemplo de API.
  • Pruebas de historia, para verificar que se cumplen correctamente las historias definidas desde negocio.

Estas pruebas nos exigen tener un conocimiento amplio de las necesidades a cumplir por lo que nos exigirán tener una gran comunicación tanto con negocio como con desarrollo, así como disponer de ejemplos que nos ayuden a diseñar las pruebas.

Al igual que en post Y que me dices de “Agile Testing Quadrants” – Parte I”  voy a aportar un poco de experiencia personal.

En una empresa anterior en la que trabajé en uno de los proyectos nos encargábamos de la calidad de las aplicaciones del cliente. El cliente nos hacia llegar un documento enorme con las pruebas que hacían manualmente para que las fuéramos automatizando. Nosotros no conocíamos la aplicación, por lo que cada dos por tres teníamos que ir con el equipo funcional para preguntarles que querían automatizar y lo más importante , que querían verificar dado que la funcionalidad era tan compleja que hasta a ellos mismos a veces les costaba conocerlo. Aquí se ve la importancia de la comunicación en el proceso del diseño de las pruebas.

En la empresa que estoy actualmente es todo muy diferente, el seguir una metodología ágil lo simplifica todo. Los QA disponemos de un tablón el que vemos lo que se está desarrollando, tenemos comunicación directa con los desarrolladores y con producto por lo que las dudas las solventamos rápidamente. Esto se resume en que el diseño de las pruebas se pueden realizar antes de que la historia esté desarrollada por lo que la automatización posterior será mucho fácil.

Conclusiones

Mediante las pruebas que se realizan en el segundo cuadrante verificaremos los requerimientos de negocio de nuestra aplicación pero para poder diseñar las pruebas es muy importante la comunicación tanto con desarrollo como con negocio.

Es posible que en algunos libros o artículos se categoricen las pruebas del segundo cuadrante como pruebas de aceptación, pero en realidad las pruebas de aceptación abarcan mucho más dado que no solo compruebas los requerimientos de negocio, también los de sistema, usabilidad y rendimiento.

Enlaces a la serie de posts

Y que me dices de “Agile Testing Quadrants” – Parte I

Introducción a “Agile Testing Quadrants”

Si alguna vez habéis trabajado con metodologías de desarrollo ágil cabe la posibilidad que conozcáis u os suene el concepto de “Agile testing quadrants”. Básicamente categoriza las pruebas de “testing” que podemos realizar en base a los diferentes propósitos.

 

Agile testing quadrants

En el gráfico se divide en cuatro cuadrantes que a su vez comparten un propósito y cada cuadrante es responsable de un tipo de pruebas en concreto.

El concepto en si no pretende ser una metodología o un marco de trabajo que se tenga que seguir a rajatabla en cada fase. Únicamente es un concepto que nos ayuda a tener focalizado en qué fase o en qué contexto aplicamos un tipo de prueba u otro ayudándonos a entender su finalidad.

Explicado esto, la idea del post es aportar un poco la visión de cada punto y en algunos puntos hablaré sobre mi experiencia y mi opinión.

Primer cuadrante – Q1

Uno de los principales pilares de la calidad de la aplicación son las pruebas unitarias o de componente dado que desde fases tempranas del desarrollo, siempre que se aplique de una forma correcta, se van a estar probando las partes de código o los métodos del código más importantes que componen nuestra aplicación.

En el desarrollo ágil, la metodología TDD (test-driven development) sería el núcleo de este cuadrante debido a que primeramente se desarrolla la prueba unitaria y se va implementando el código de la lógica de la aplicación mediante la refactorización, lo que aporta mayor garantía de calidad.

En este punto creo que puedo aportar cierta experiencia. Cuando comencé a desarrollar en la primera empresa que trabajé no realizábamos pruebas unitarias y menos utilizamos metodologías ágiles, esto se debía en parte a falta de conocimiento y en parte a las dichosas fechas.

Esto suponía que un cambio en el código nos podía “romper” ciertas funcionalidad que en “teoría” funcionaban correctamente, por lo que invertíamos mayor esfuerzo en arreglar lo que rompíamos o en hacer pruebas.

Lo cierto es que el desconocimiento no me hacía ver gravedad que podía llegar a tener. Con el paso del tiempo empezamos a involucrarnos más en proyectos de QA, lo que me llevó a aprender mucho y a ver el resultado de que en un aplicación no se implementará una buena estrategia de aseguramiento de la calidad en fases tempranas (el 95% de los proyectos que vi no disponían de ningún tipo de prueba unitaria y ni lo tenían en mente).

Y ahora que trabajo en una empresa como QA y que seguimos una metodología ágil veo los beneficios de disponer de unas buenas pruebas unitarias y el uso de la metodología TDD, lo que verdaderamente nos da una mayor garantía a la hora de sacar el producto al público.

Conclusiones

Más que una conclusión, lo que me gustaría trasladar es la importancia de implementar la calidad de la aplicación desde la fase inicial de su desarrollo e incluso conceptualización.

A medida que vayamos avanzando con esta serie de posts veremos como los cuadrantes nos aportan una visión de que pruebas podemos aplicar en cada fase para garantizar la calidad de nuestra aplicación.

Enlaces a la serie de posts

Lectura recomendada