Automatización de pruebas: principios, prácticas y herramientas

Finalmente, me hice un rato y mandé mi propuesta de sesión sobre este tema a Agiles 2014. Para quienes gusten darme feedback, pueden ver la propuesta completa en el sistema de call for papers de la conferencia.

Una cuestión que no está mencionada en la propuesta es qué fue lo que me llevó a proponer una sesión sobre este tema.

Como programador y sobre todo desde que me metí en el mundo Smalltalk, las pruebas unitarias automatizadas se volvieron un artefacto imprescindible en mi trabajo. Al ser Smalltalk un lenguaje de tipado dinámico no contaba con la (falsa) seguridad que proveen los compiladores en los lenguajes de tipado estático. Por esto me sentía obligado a escribir pruebas unitarias automatizadas para tener cierto nivel de seguridad de que no estaba rompiendo mi proyecto. Tiempo más tarde cuando comencé a trabajar en la implementación de la práctica de continuous delivery tomé conciencia de que con automatizar las pruebas unitarias y de componentes no era suficiente. Fue en ese momento que comencé a meterme gradualmente en las cuestiones de automatización de pruebas de aceptación de usuario. En ese sentido trabajé con Juan Gabardini en preparar un curso de automatización de pruebas y tiempo después comencé a trabajar con Pablo Tobia (alto tester) en el armado de una materia de testing que finalmente materializamos en el curso que dictamos en FIUBA. Al mismo tiempo para ganar más experiencia de campo logré meterme a trabajar como Software Engineer in Test en un proyecto de automatización de pruebas de un sistema de facturación. Todo esto me ayudó a ganar experiencia e incorporar muchísimo conocimiento sobre esta temática.

Como de costumbre, si la sesión es aceptada en Ágiles 2014, intentaré hacer una prueba previa en uno de los encuentros de la comunidad ágile@BsAs, mm, en realidad creo que la prueba lo voy a hacer igual más allá de que sesión sea aceptada en Agiles 2014 o no.

Taller (experimental) de Testing

Hace varios de meses comenzamos a trabajar con mi colega Pablo Tobia en el armado de la un materia de Testing. Leímos, experimentamos, debatimos, hablamos con otros colegas y finalmente decidimos pasar a la acción: vamos a dictar un Taller de testing. El objetivo central de este taller es obtener feedback de lo que hemos armado para poder refinarlo de cara a presentarlo formalmente como una materia. A continuación comparto un poco más de información en forma de «Preguntas frecuentes» para los posibles interesados.

¿Qué duración tiene? Son 4 clases de 3 horas cada una. Adicionalmente al tiempo de clase se espera que los alumnos dediquen cierto tiempo (entre 1 y 2 horas semanales) a la realización de algunas prácticas.

¿Qué costo tiene el curso? Ninguno, es gratuito aunque posiblemente le pidamos a los alumnos algún tipo de contraprestación como por ejemplo traer alimentos para donar a un comedor comunitario o algo por el estilo.

¿Cuando se dicta? Aún no lo tenemos del todo definido pero la idea es hacerlo durante Julio aprovechando que no hay clases. Seguramente sea un día por semana a partir de las 18 o 19 horas.

¿Da créditos para la carrera? No, el taller es absolutamente extra-curricular.

¿Qué conocimiento previo necesito? El taller es muy práctico y está orientado a la automatización, con lo cual se espera que todo alumno pueda programar. En principio trabajaremos con Java y Ruby. Si no sabes de ninguno de estos lenguajes y crees que puedes darte maña para aprenderlos, no hay problema, pero nosotros no vamos a explicar Java ni Ruby. Al mismo tiempo, son necesarios cierto conocimiento de aplicaciones web (http, html, etc) y de metodologías de desarrollo de software.

¿Cuál es el temario del curso? En forma resumida podemos decir que veremos algunas cuestiones conceptuales, varias cuestiones de índole práctica y diversas herramientas como ser Cucumber, Fit, Watir, RSpec, JUnit, CasperJS y Selenium.

¿Cómo me anoto? Si estas interesado participar, te pedimos que completes este formulario.

 

 

 

Libros de testing

Luego de la inquietud planteada sobre mi percepción del testing en la industria y la academia, me dediqué a profundizar en el tema. Por un lado conociendo herramientas y buscando oportunidades laborales relacionadas al tema y por otro lado leyendo al respecto. Comparto aquí la lista de los principales libros que he leído/consultado:

 

 

 

 

Primeros pasos con Cucumber-JVM

Hace poco más de dos meses estoy trabajando casi cotidianamente con Cucumber-JVM y como consecuencia de ello he aprendido muchísimo sobre dicha herramienta. Si bien ya tenía bastante experiencia con la implementación Cucumber-Ruby, resulta que la implementación Java tiene sus particularidades.

Para compartir lo que he ido aprendiendo he decidido grabar una serie de videos. He aquí el primero de ellos: Introducción a Cucumber-JVM, espero les resulte útil.

 

Implementación de Step Definitions en Cucumber-JVM

Continuando con los dilemas del uso de cucumber, luego de un par de reuniones con los analistas/testers del proyecto, tomamos algunas decisiones:

  • Escribir los steps con las menor cantidad de parámetros posibles
  • Agrupar los step definitions en base a conceptos de negocio
  • Utilitzar Step definitions con estado (stateful)

A partir de esto, el flujo de trabajo es: los analistas/testers identifican los casos de tests y los expresan como escenarios usando lenguaje Gherkin. Luego usando las anotaciones de Cucumber-JVM yo genero los métodos que implementan los pasos de los escenarios. Estos métodos son los que se conocen como «Step definitions». Hasta aquí llega la herramienta. La forma en que se implementan los Step Definitions depende de cómo sea la aplicación que se pretende testear. Si quisiéramos testear una aplicación web, posiblemente usariamos el driver de Selenium. En mi caso, tengo que testear un sistema de facturación a través de una interfaz propietaria basada en mensajes XML. Más allá de la interfaz hay dos cuestiones que requieren interactuar directamente con la base de datos del sistema:

  1. Limpiar los datos luego de la ejecución de cada test
  2. Realizar ciertas verificaciones (asserts) sobre los datos generados por el sistema que no se encuentran disponibles en la interfaz

Para lidiar con todas estas cuestiones he generado un conjunto de clases (¿micro-framework?) que agrupan código común y que me permiten elevar un poco el nivel de abstracción. cucumber_domain   Scenario, no es una clase, es un caso de prueba especificado en lenguaje Gherkin en un archivo de extensión .feature (un feature suele contener varios scenarios). StepsDefinition no es una clase, sino que son métodos agrupados en clases según criterios de negocio. BusinessAction, son clases que agrupan operaciones de alto nivel con granularidad de negocio. ScenarioContext, es un singleton donde se almacena el estado a lo largo de la ejecución de los distintos steps que conforman un scenario. Este contexto es reseteado cada vez que se ejecuta un scenario. Driver, es una clase con operaciones «de bajo nivel» que permite la interacción con el sistema que se está testeando. DBHelper, es una clase con operaciones para interactuar con la base de datos, se utiliza para resetear el estado del sistema y también para realizar algunas verificaciones que no pueden hacer utilizando el driver/api. Los siguientes diagramas muestran la interacción de estos componentes. cucumber_sequence1     cucumber_sequence2

Cucumber: teoría y práctica

Teoría: Cucumber es una herramienta para hacer BDD y como tal logró su difusión. BDD una de las técnicas de la familia Test-First.

Práctica: uno puede utilizar Cucumber sin hacer BDD ni Test-First. O sea, es posible usar Cucumber para escribir pruebas sobre aplicaciones ya existentes.

Personalmente hace más de dos años que usé Cucumber por primera vez y desde entonces he leído bastante sobre al respecto y en la gran mayoría de los casos se lo trata como una herramienta de BDD. Sin embargo casi toda la gente que conozco que usa Cucumber (y que no es mucha) no lo usa para hacer BDD, sino que lo utiliza como una herramienta tradicional de automatización de tests.

*nota: al decir Cucumber, hablo de forma genérica, sin centrarme en ninguna implementación particular.

cucumber_logo

 

 

Los dilemas del uso de Gherkin/Cucumber

Como mencioné anteriormente, estoy trabajando un proyecto ocupando el rol de Software Engineer in Test (SET). Una de las primeras cuestiones que debí resolver en el proyecto fue acordar con los analistas/testers la convenciones para escribir los tests con Gherkin. Todo aquel que haya trabajado con Gherkin en algún momento seguramente se ha enfrentado a los diversos dilemas que plantea el uso de la herramienta.

Dilema 1

  • Escribir steps con parámetros, que permiten un alto reuso de steps definitions disminuyendo la cantidad necesaria de glue-code
  • Escribir steps sin parámetros, que permiten un mayor nivel de abstracción y expresividad, pero que al mismo tiempo requieren de más glue-code

Dilema 2

  • Agrupar los steps definitions por feature, lo cual posiblemente genere muchos archivos de steps definitions y también repetición de glue-code, pero que facilita la trazabilidad entre los archivos de features y los archivos de steps definitions
  • Agrupar los steps definitions por concepto de negocio, lo cual ayuda a reducir la cantidad de archivos y la posible repetición de código, pero que puede dificultar la trazabilidad entre archivos de features y archivos de steps definitions

Dilema 3

  • Hacer steps «stateless» (que no dependen de datos de contexto) lo cual permite mayor reuso, pero que obliga a pasar la información de contexto como parámetro de los steps
  • Hacer steps «stateful» (que sí dependen de datos del contexto) lo cual permite generar steps más claros yreducir/omitir los parámetros en los steps, pero que disminuye el reuso de steps y obliga a generar código adicional para el manejo del contexto

En todos los dilemas planteados existen más alternativas que las mencionadas, de hecho las alternativas aquí planteadas son en cierto modo extremas pero sirven para ejemplificar algunas de las cuestiones que debemos definir al trabajar con esta herramienta.

Al mismo tiempo hay algunas cuestiones adicionales a considerar dependiendo de la implementación de cucumber que utilicemos. Por ejemplo: la implementación Ruby es un DSL que permite fácilmente compartir estado entre los steps definitions independientemente de la forma en que los agrupemos, mientras que en la implementación Java (Cucumber-JVM) sólo es posible (en principio) compartir estado entre los steps definitions que esten agrupados en la misma clase.

Todas estas cosas son las que estuve definiendo la primer semana de proyecto. Ahora estoy trabajando en generar un «micro framework» (básicamente algunas clases helpers) que me faciliten la implementación de los steps definitions.

Continuará…

 

 

 

Software Engineer in Test

Uno de los libros que leí este verano fue «How Google Test Software«, el cual describe entre otras cosas la estructura de equipo y roles usada por Google. Entre los roles mencionados hay 3 que captaron principalmente mi atención.

Software Engineer, también llamado en el libro feature developer, es quien construye la funcionalidad deseada por el usuario. Escribe el código de las funcionalidad junto con sus correspondientes pruebas unitarias.

Test Engineer, también llamado en el libro user developer, es el responsable desde la perspectiva del usuario de todas aquellas cuestiones relacionadas a la calidad. Se encarga de la automatización de los escenarios del uso.

Software Engineer in Test, también llamado en el libro test developer, es el responsable de asistir al Software Engineer en la escritura de los test proveyendo herramientas y frameworks de soporte que faciliten la escritura de los mismos y permitan cumplir con las diversas cuestiones de calidad.

Por si la descripción de los roles no es clara: el software engineer es responsable de construir las  funcionalidades y probarlas, el Software Engineer in Test, lo ayuda en estas tareas proveyendo herramientas y incluso escribiendo algunos tests más grandes (no unitarios). El Test Engineer prueba las funcionalidades desde una óptica más general, viendo más el bosque (sistema como un todo) que el árbol (funcionalidades particulares).

Es este último rol, Software Engineer in Test, el que más llamó mi atención, creo que en parte por el hecho de que me gustaría contar con alguien así cuando me desempeño como Software Engineer/Feature developer.

Casualmente por esas vueltas que tiene la vida, la semana pasada empecé a trabajar en un nuevo proyecto ocupando un rol que bien podría definir como Software Engineer in Test. En el proyecto hay un conjunto de analistas que escriben/describen/especifican la funcionalidad del sistema utilizanzo lenguaje Gherkin y yo me encargo de escribir el denominado «glue code» para que esas descripciones/especificaciones pueden ejecutarse de forma automatizada. Para esto básicamente escribo código Java usando Cucumber-JVM. Dado que estoy trabajando part-time en este proyecto, aún es muy poco lo que he hecho, pero estoy muy entusiasmado.

Cierro este artículo con una de las frases que más me gustó del libro:

«Test is just another feature of the application, and SETs are the owner of the testing feature.»

 

Javascript tests running on Jenkins

Nowadays, no matter what technology you use to build your web application, it is almost sure you will need to write some JavaScript code. At the same Javascript script code is not only used to animate the web pages, it is also used to handle validations and application flow. Because of this, everyday is more needed to write unit tests for the Javascript code.

There are several unit testing frameworks for Javascript. In my case I choose Qunit, that is testing framework developed by the jQuery guys.

Of course that in order to be able to write unit tests for your code, you will need to follow some design guidelines, but that is part of another post. Let’s suppose you followed that guidelines and now you want to write some test, these are the steps you should follow to run your tests:

  1. Download qunit.js
  2. Download qunit.css
  3. Write your tests in a javascript file
  4. Create a html page referencing the 3 previous files

With these 4 steps you are almost done, open the html file and you will have your tests executed.

What is missing, is how to run these tests in the build server. The interesting point here is that to run Javascript t tests we need a Javascript engine. In a develop machine, it is not a problem, you can use your browser, but in the build server is not so easy. The approach I took was to use PhantomJS, a tool that among other things, can run Javascript without needing a browser.

So using PhantomJS and MSbuild I was able to have my Jenkins running my Javascript tests.

Here you can download a running example.