Más sobre los test automáticos

 

Comenté ayer que estaba jugando con fest-swing y otras herramientas para test automáticos de pruebas de las interfaces gráficas de usuario. Pues bien, hoy he seguido un poco y he conseguido resolver la mayor parte de los problemas que se me presentaron. Eran, por supuesto, culpa mía, de no conocer la herramienta y de la mala costumbre de jugar el ensayo y error en vez de leerse la documentación.

Por un lado, en vez de bajarme fest-swing de la página de fest-swing, usé el repositorio maven que hay para ello, dejando que fuera maven el que se bajara el jar de fest-swing y todas sus dependencias. Entiendo que esto no tiene mucho que ver (más bien nada) con los problemas que se me presentaron.

El segundo punto, y este sí es importante, es que si hacemos el ejemplo tonto de test que viene con fest-swing no hay ningún problema, sale bien a la primera. Pero si ejecutamos una batería de test con fest-swing, es muy importante reiniciar los recursos que usa fest-swing. Esto se traduce que en el método tearDown() (que JUnit ejecuta después de cada test), debemos hacer la llamada correspondiente

private FrameFixture window; // Clase de Fest-Swing con la ventana principal.

public void tearDown() {
   window.cleanUp();  // reiniciar recursos
}

Y esto ha solucionado gran parte de los problemas que tenía. Ahora las ventanas de test sí salen cuando se ejecutan desde maven y no hacen tantas cosas raras cuando se ejecutan desde eclipse.

Otro tema importante es que aunque Fest-Swing se encarga de acceder a los componentes en el hilo de tratamiento de eventos de swing, es posible que el orden de estos eventos no sea el que esperamos. Si nuestro test manda visualizar una ventana, he encontrado útil esperar a que dicha ventana esté realmente visible antes de proseguir con el test. Esto se puede conseguir con la llamada a window.requireVisible() de fest-swing. Esta llamada hace fallar el test si la ventana no está visible, pero espera un tiempo prudencial antes de cantar el fallo. De esta forma, la llamada se queda bloqueada hasta que la ventana realmente está visible, o hasta que pasa un tiempo excesivo de espera (configurable, por supuesto).

Lo que no he conseguido es que desde eclipse los test se ejecuten dando resultados siempre. Sí es cierto que con todo esto parece que falla menos, pero siguen saliéndome barras grises o negras (en vez de verdes o rojas) de vez en cuando.

Una vez conseguido que todo funcione más o menos correctamente, lo he metido en Subversion y he esperado a que el sistema de integración continua (Hudson) compilara y ejecutara los test. A pesar de las advertencias en la documentación de fest-swing de que puede haber problemas con la integración continua, todo ha ido sobre ruedas y sin problemas.

Otra característica que me ha parecido interesante de fest-swing, aunque no la he probado, es que si un test falla, fest-swing puede capturar y almacenar la pantalla en el momento que se produce el fallo. De esta forma, viendo la foto de nuestra interfaz gráfica de usuario con el fallo, podemos ver si realmente hay algo incorrecto o el fallo se ha producido por otra circunstancia. Por ejemplo, que la ventana de que "windows se ha actualizado" haya salido justo encima de nuestra interfaz justo cuando la estamos testeando.

Así que de momento fest-swing queda incorporado en mi trabajo como herramienta para hacer test de interfaces gráficas de usuario. Sólo me falta ir convenciendo a mis "compis" para que también la usen.

Comenté también en el post anterior que quería probar Abbott. Bien, después del éxito con fest-swing, no lo he hecho. Pero leyendo la documentación de Abbott, he visto una característica también interesante. Abbott, ¿cómo no?, viene con Costello, una aplicación que permite ejecutar nuestra interfaz de usuario de forma normal (a través de su método main()) y actuar manualmente sobre ella. Costello se encargará de capturar toda nuestra interacción con ella (a modo de grabación), de forma que luego Costello puede reproducirla una y otra vez sobre nuestra aplicación, testeando que los resultados son los mismos. Es una forma interesante de hacer los test, sin necesidad de programar demasiado. A pesar de que usaremos fest-swing, probaré Abbott y Costello en algún momento, para ver si se puede testear el sistema completo en el entorno de pruebas.

Test automáticos de interfaces gráficas de usuario

 

Por fin, después de una larga temporada adaptando una y otra vez el mismo software ya hecho a distintos proyectos, ha llegado el momento de empezar a hacer algo nuevo. Vamos a pasar a java unas viejas interfaces gráficas de usuario que teníamos en C++. Por supuesto y con mis ganas de aplicar (y aprender) las buenas costumbres de programación, voy a intentar hacer la parte que me toca siguiendo TDD. Pero, amigo Sancho, con la iglesia hemos topado. Una de las cosas que tradicionalmente se reconoce que son difíciles de probar automáticamente son, precisamente, las interfaces gráficas de usuario.

En una aplicación java SWING, los test básicamente consisten en coger la ventana e ir buscando en los componentes que contienen, recursivamente, hasta que se encuentra el que se busca. Una vez encontrado, actuamos sobre él, haciendo click, metiendo un texto, leyendo su contenido o lo que sea que necesitemos hacer para realizar el test automáticamente. También la clase java.awt.Robot nos permite simular eventos de ratón y teclado sobre los componentes. Pero ni buscar componentes por las ventanas, ni usar la clase Robot es precisamente una tarea cómoda. Por fortuna, hay librerías que nos ayudan a hacer estas tareas y en definitiva, a realizar los test automáticos. Así que a probar esas librerías toca.

La primera que he probado ha sido FEST-Swing, quizás la más conocida para aplicaciones de escritorio con java. La librería está muy bien y contiene características muy interesantes. Las que más me han llamado la atención:

  • Según recomendación de java, todos los accesos a ventanas deben hacerse en el hilo de refresco de ventanas y tratamiento de eventos que nos proporciona java (EDT Event dispatch Thread). Pues bien, una simple configuración de FEST en el test hace que salte si accedemos a los componentes SWING fuera de ese hilo.
  • Precisamente ese hilo es un poco rollo. Nuestro test no se ejecuta en ese thread EDT y si el código que testeamos mete algo en un componente SWING usando el thread EDT (como se recomienda), nuestro test debe esperar a que el thread EDT termine antes de verificar el contenido del componente. Pues bien, FEST nos hace esto totalmente transparente. Cuando con FEST accedemos a un componente para ver su contenido, FEST espera que terminen los hilos EDT.
  • Aunque al principio parece raro, es realmente sencillo de usar. Podemos buscar en general cualquier componente con un método simple, indicando qué tipo de componente buscamos (JTextFiel, JLabel, etc), por su nombre (si hemos tenido la precaución de ponérselo con setName()) o haciéndonos un filtro a medida (un Matcher)

Pero no es oro todo lo que reluce. Me he encontrado con dos problemas que me van a dificultar seriamente su uso, más un pequeño problemilla.

  • El pequeño problemilla es que si ejecuto un test desde eclipse, a veces parece que no se ejecuta el test. Cuando ejecutamos un test en eclipse, al final sale una barra verde o roja, indicando si el test pasa o no. Pues resulta que, de forma aleatoria, el test termina y dicha barrita queda en negro o en gris, como si eclipse no detectara que el test ha terminado. Bueno, no es grave, puesto que no voy a ejecutar habitualmente los test con eclipse y lo peor que puede pasar es que tenga que darle dos o tres veces hasta obtener la barra verde o roja.
  • Un problema más serio lo he tenido con maven. Cuando ejecuto el test en eclipse, FEST visualiza las ventanas bajo test, se hace el test y pasa el test o falla (o se queda en gris/negro). Ejecutando el mismo test desde maven, ni siquiera sale la ventana y el test falla sistemáticamente. Investigaré en este tema, pero si no consigo solucionarlo, descartaré el uso de FEST en el entorno que trabajo.
  • Y un segundo posible problema es la integración continua. Hudson se encarga de compilar y pasar los test de nuestros proyectos todas las noches. FEST requiere que la ventana se visualice y por tanto, requiere que Hudson corra en un terminal abierto en sesión, sin salvapantallas ni nada que impida la correcta visualización de la ventana. En la documentación de FEST indican varias formas para solucionar problemas con la integración continua. Me pondré con ellas si consigo pasar el punto anterior, lo de ejecutar los test con maven, ya que si hudson ejecuta maven y maven no muestra las ventanas, me da igual que haya o no pantalla disponible.

Después de esto, fui a buscar otra herramienta y me topé con uispec4j. Mucho más simple que FEST de uso (aunque menos potente) y puede cumplir para test no excesivamente ambiciosos. A diferencia de FEST, no requiere que las ventanas se hagan visibles. Esto seguramente dé menos problemas a la hora de integración continua, pero posiblemente haga que los test sean menos reales. Tampoco controla el acceso a los componentes a través del thread EDT, por lo que las esperas por dicho thread debemos codificarlas en nuestro test. Así que nada, me puse a probarla y ¿cómo no?, me encontré con un par de problemillas.

  • Al igual que FEST, al ejecutar los test con eclipse, a veces la barra no queda ni verde ni roja, sino gris claro o negro. Esto ya hace pensar que no es problema ni de FEST ni de uispect4j, sino quizás un test mal hecho por mi parte o a algún problema con mi eclipse. Tengo que probar en casa.
  • Al ejecutar los test, me salta una fea excepción. Buscando en google, veo que hay un problema cuando juntas wndows xp, java 6 y uispec4j. ¡¡ qué casualidad !! ¡¡ justo mi configuración !!.

En fin, sigo peleándome a ver si consigo que alguna de estas herramientas me funcione correctamente. También me gustaría echar un ojo a abbott, herramienta similar aunque quizás menos conocida.

Por cierto, quiero dejar claro que no estoy diciendo que FEST o uispec4j estén mal o no funcionen correctamente. Simplemente estoy contando lo que me ha pasado trabajando dos o tres días con ellas mientras hacía el código real de mi aplicación. Pueden ser fallos de las librerías, de mi configuración concreta, de mi código que haga cosas raras o de que estoy pagando la novatada haciendo mis primeros test de este tipo con este tipo de herramientas.