Contenido

Tests de aceptación con Robot

Como bien sabéis, las pruebas es algo que me inquieta bastante. Y creo que las pruebas de aceptación son especialmente importantes para asegurar la calidad final del producto en su conjunto, así como para dirigir el desarrollo.

Hace ya algún tiempo que escribí sobre Atheist en artículos como Atheist: Probando módulos C, Atheist, No seas crédulo ¡¡Prueba!! y Pruebas web: selenium + atheist. Atheist es un framework estupendo, pero quizá muy poco utilizado.

En este caso vamos a ver otro framework diferente y muy utilizado, llamado Robot y traído de la mano de Google.

Testing

¿Qué es RobotFramework?

RobotFramework consiste en una serie de reglas para crear archivos de especificación similares a RSpec, al menos en cuanto a intención. En Robot los test están especificados en tablas.

La intención es la siguiente:

  1. Crear un archivo .txt, .robot o… bueno, admite varios formatos, con una o varias tablas de tests.
  2. Si fuera necesario, crear un archivo Python o Java con nuevas keywords que poder utilizar en las tablas.

Y ya está.

¿Sencillo? Justamente de eso se trata.

Ejemplo

Y, sin más, vamos con un ejemplo.

Supongamos que tenemos un pequeño programa que, dado un número, devuelve el Fibonacci:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#!/usr/bin/env python
import sys

def fibo(n):
    return fibo(n-1) + fibo(n-2) if n > 2 else 1

def main():
    print(fibo(int(sys.argv[1])))

if __name__ == '__main__':
    main()

Lo he hecho en Python, pero realmente daría igual el lenguaje.

Vamos a comprobar que funciona. Para ello, creamos el directorio “tests” y dentro vamos a crear una suite. Crear una suite es muy sencillo: todo directorio y todo archivo es ya una suite. Dentro meteremos un test, que consiste en una tabla:

1
2
3
4
5
6
7
8
*** Settings ***
Library    Process

*** Test Cases ***
Fibo of 1 is 1
    ${result} =       Run Process         ./fibonacci.py     1
    Should Be Equal   ${result.stdout}    1
    Should Be Equal As Integers      ${result.rc}   0

Robot admite varios formatos de archivo; en este caso he optado por la opción texto plano. Luego veremos otros formatos.

Lo primero que podemos ver es la tabla Settings, que entre otras cosas permite cargar una librería. Para ello usamos la keyword Library y, separado por más de 2 espacios, el nombre de la librería a utilizar.

A continuación está la tabla Test Cases, donde se definen los casos de uso. Veréis que el formato es sencillo: en la primera fila está el nombre del test, y cada una de las acciones están ligeramente indentadas.

En la primera acción se asigna a la variable result el resultado de la acción, que consiste en invocar la keyword Run Process con los parámetros .\fibonacci.py y 1.

En la segunda acción, se comprueba que el valor de result.output es 1, usando la keyword Should be equal.

En la tercera acción, se comprueba que el valor de result.rc (el valor de retorno) es 1, usando la keyword Should be equal As Integers.

Si ahora ejecutamos el test, obtendremos lo siguiente:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ pybot tests/example1.robot
==============================================================================
Example1
==============================================================================
Fibo of 1 is 1                                                        | PASS |
------------------------------------------------------------------------------
Example1                                                              | PASS |
1 critical test, 1 passed, 0 failed
1 test total, 1 passed, 0 failed
==============================================================================
Output:  /home/miguel/Sandbox/python/robot/output.xml
Log:     /home/miguel/Sandbox/python/robot/log.html
Report:  /home/miguel/Sandbox/python/robot/report.html

Como vemos, el test pasa, y nos ha dejado la salida en los archivos output.xml, log.html y report.html.

Podemos uno de estos archivos:

Tablas como tablas

A lo mejor resulta difícil ver las tablas en este formato, así que vamos a probar a cambiarlo. El test va a ser prácticamente igual:

1
2
3
4
5
6
7
8
| *Setting* | *Value* |
| Library   | Process |


| *Test Case*    | *Action*                    | *Argument*        |
| Fibo of 2 is 1 | ${result} =                 | Run Process       | ./fibonacci.py | 2
|                | Should Be Equal             | ${result.stdout}  | 1
|                | Should Be Equal As Integers | ${result.rc}      | 0

Como vemos, ahora el separador es el símbolo |. Por lo demás, básicamente lo mismo.

Otros formatos

Hay otros formatos, como HTML, RST (que no recomiendo, ya que internamente lo convierte a HTML, lo que puede ser más lento, y requiere la librería docutils), TSV, …

Ampliando el lenguaje

Como vemos, es básicamente un lenguaje de programación, en el que las instrucciones son instrucciones como Run Process, Should Be Equal o Should Be Equal As Integers. Pero… ¿Y si queremos usar nuestra propia instrucción?

Pues es sencillo. Basta con crear un archivo Python o Java (este último no lo explicaré) con la función a utilizar:

1
2
def check_fibonacci_result(result, expected):
    print "hola"

Y ya podemos utilizarla (ojo a la separación de palabras y el uso de mayúsculas y minúsculas):

1
2
3
4
5
6
| *Setting* | *Value* |
| Library   | ${EXECDIR}/lib/fibotest.py |


| *Test Case*    | *Action*               | *Argument* | *expected*
| Fibo of 2 is 1 | Check Fibonacci Result | 2          | 1

Y así podemos crear nuestro propio lenguaje de tests.

Librerías para ampliar el lenguaje

RobotFramework viene con algunas librerías para permitirnos realizar las operaciones más típicas:

  • Tareas relacionadas con el sistema operativo
  • Posibilidad de capturar el escritorio
  • Conexión mediante telnet
  • Modo interactivo, en el que se solicita información al usuario
  • etc.

Así mismo, hay otras librerías que permiten realizar otras operaciones comunes, como utilizar Selenium o Android.

Generación de informes

Algo interesante es saber cómo hace Robot para generar los informes. Lo primero que hace es crear un archivo output.xml con los resultados de la ejecución. Este archivo se postprocesa para generar los archivos .html resultantes.

Estos pasos ofrecen una posibilidad adicional: La de utilizar la información del archivo output.xml como reentrada. Así, utilizando rebot en lugar de pytbot podemos volver a ejecutar los tests fallidos, lo que parcheará el archivo output.xml como si siempre hubieran funcionado, evitando así los tests inestables.

Conclusión

RobotFramework es una buena opción a la hora de elegir un sistema de pruebas de aceptación. Además está soportado por Google, lo que siempre es un extra.

Sin embargo, los informes resultan algo feos y no es sencillo cambiarles el estilo o embeberlos en otra página más grande sin usar iframes. Además, son poco adecuados para presentárselos a los ejecutivos o al cliente, ya que son más técnicos que otra cosa.

Un punto positivo es lo de poder escribir los fixtures tanto en Python como en Java. La posibilidad de usar distintos lenguajes en este caso siempre es algo que puede venir bien.

En un próximo artículo hablaremos de Fitnesse, otra solución para tests de aceptación.