Contenido

Selenium y QA Automation

En el mundo de la automatización de pruebas, Selenium arrasa. Existen otras alternativas, pero lo cierto es que todo el mundo utiliza Selenium.

Hay distintas formas de utilizarlo, y aquí veremos algunas de ellas. He elegido Python porque es mi lenguaje favorito y Java porque es el lenguaje en el que está hecho Selenium.

Selenium

¿Qué es?

Selenium es un conjunto de herramientas que permiten la automatización de navegaciones Web. En general, esto tiene dos usos:

  • Automatizar pruebas web.
  • Automatizar tareas web muy repetitivas.

En general, y aunque puede usarse para navegar, llamaremos “Test” a cada uno de los scripts que usemos.

Probablemente leáis en la web acerca de otra opción, llamada Webdriver, pero éste es el nombre que recibe Selenium 2. A veces la información al respecto está un poco confusa.

¿Cómo funciona?

Existen distintas maneras de usarlo, algunas mejores y otras peores:

  • Mediante el Selenium IDE.
  • Usando el driver adecuado.
  • Arrancando un servidor y conectándonos a él
  • En modo Hub.

Veremos cada uno de ellos en las siguientes secciones.

Selenium IDE

Consiste en un plugin para Firefox que nos permitirá guardar las acciones que realicemos para después reproducirlas. Realmente lo que hace es guardar un script que después lanzará contra el servidor (ver siguiente apartado).

Ventajas:

  • Es muy fácil para comenzar y realizar algunas pruebas básicas.
  • Todo mediante clicks de ratón.
  • No es necesario un aprendizaje previo.

Desventajas:

  • Aunque al principio parece muy interesante, pronto se descubre que realizar las pruebas así es lento.
  • No se puede reutilizar nada. Hay que comenzar desde el principio.
  • No permite ningún tipo de organización, más allá de agrupar en módulos.
  • Es necesario tener el navegador arrancado.
  • Sólo funciona con Firefox.
  • Las pruebas tienen que ser locales; no se pueden lanzar en remoto.

En general es un modo que puede ser interesante para aprender, para ver cómo hacer algo que no sabemos hacer a mano o para scriptar una navegación frecuente o dos sobre una página.

Driver especifico

Esta opción es NO usar Selenium, sino un driver a medida, como el ChromeDriver. La propia API ya puede utilizar el driver adecuado y así realizar la operación adecuada, sin necesidad de ejecutar servidores.

Ventajas:

  • Fácil para comenzar a usar la API.
  • Permite organizar el código.
  • Abrirá el navegador adecuado.
  • Ofrece una API común a todos los navegadores.

Desventajas:

  • El código es dependiente del navegador.
  • No se puede ejecutar remotamente.

Si usamos Chrome, usando el ChromeDriver tendríamos mucha más versatilidad, pero la API no sería común con otros navegadores.

Servidor

Al arrancar el servidor y usar una API podremos obtener mayor control y realizar las pruebas en remoto. En estas pruebas podremos indicarle al servidor qué navegador queremos arrancar para ejecutar las pruebas.

Luego veremos cómo usar esta API.

Ventajas:

  • Se puede utilizar de forma remota.
  • El servidor puede estar arrancado y abrirá el navegador adecuado.
  • El código se puede organizar como si fuera de producción. Esto también permite guardarlo en un DVCS.

Desventajas:

  • Sólo puede ejecutar un script simultáneamente.
  • Perdemos parte de la potencia de cada API individual, a favor de una API común a todos los navegadores.

Modo Hub

En este caso lo que tenemos son servidores que se conectan a otro servidor principal, al que llamaremos Hub. Este Hub mantiene una lista ("pool") de tests que irá repartiendo entre sus “clientes”.

Esto permite utilizar distintas máquinas para ejecutar los tests de manera simultánea. Por lo demás, funciona igual que el modo servidor, y cualquier script que hayamos creado antes nos valdrá.

Ventajas:

  • Todas las del modo servidor
  • Puede ejecutar tantos scripts simultáneos como servidores se conecten a él.

Desventajas:

  • Arquitectura un poco más compleja
  • Seguimos perdiendo parte de la potencia de cada API individual.

Al lío

Pues ya sabemos lo que hay, así que vamos a hacer alguna cosa. Crearemos un script que se puede ejecutar en modo Hub o servidor. Por simplicidad, aquí contaremos cómo usar el modo servidor.

Lo primero es arrancar un servidor de selenium. Para ello, nos bajamos de la web la última versión y ejecutamos:

1
2
3
4
$ java -jar selenium-server-standalone-2.30.0.jar
[...]
08:55:15.446 INFO - Started SocketListener on 0.0.0.0:4444
[...]

Y ahí se queda funcionando. He copiado una de las líneas de la salida para que veáis dónde estará escuchando: en localhost, usando el puerto 4444.

Ahora necesitamos algo que probar… Lo más sencillo es levantar un servidor en nuestra máquina y así podremos navegar por los directorios. Y hacer esto con python es muy sencillo. Los que no tengáis Python instalado, podéis usar cualquier web como ejemplo:

1
2
$ python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...

Ale, ya tenemos un servidor sirviendo algo que podemos probar. Espero que lo hayáis ejecutado en algún directorio que tenga algún fichero XD

Nuestro primer script

Vamos a hacer un script que abra un Chrome y que compruebe algo básico de la página: el título:

Java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package org.magmax.selenium;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import org.openqa.selenium.Capabilities;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;


public class App
{
    public static void main( String[] args ) throws MalformedURLException
    {
      /*
      URL url = new URL("https://localhost:4444/wd/hub");
      Map<String, String> map = new HashMap<String, String>();
      map.put("browserName", "firefox");
      Capabilities capabilities = new DesiredCapabilities(map);
      RemoteWebDriver driver = new RemoteWebDriver(url, capabilities );
       */
      FirefoxDriver driver = new FirefoxDriver();
      try {
        driver.get("https://localhost:8000");
        if (!driver.getTitle().equals("Directory listing for /"))
          throw new AssertionError("The title do not match");
        System.out.println("Everything OK");
      } finally {
        driver.close();
      }
    }
}

Y el POM si usáis Maven:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<project xmlns="https://maven.apache.org/POM/4.0.0"
  xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.magmax</groupId>
  <artifactId>selenium</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>selenium</name>
  <url>https://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
          <archive>
            <manifest>
              <mainClass>org.magmax.selenium.Main</mainClass>
            </manifest>
          </archive>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
        <scope>test</scope>
      </dependency>
    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-java</artifactId>
        <version>2.31.0</version>
    </dependency>
    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-chrome-driver</artifactId>
      <version>2.31.0</version>
    </dependency>
  </dependencies>

</project>

NOTA: El código que quería mostraros es el comentado. De esa manera sólo dependíamos de una cadena para seleccionar el Browser a utilizar, sin embargo no he conseguido hacer que funcione. Si alguien sabe por qué, le estaría muy agradecido.

Python

En python necesitaremos instalar python-selenium, que es paquete Debian.

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

from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException

driver = webdriver.Remote('https://localhost:4444/wd/hub', {'browserName': 'firefox'})
try:
    driver.get('https://localhost:8000')
    assert driver.title == "Directory listing for /"
    print 'Everything ok'
finally:
    driver.close()

Y ya está.

Comentarios

Como podréis suponer, si en lugar de “firefox” queremos usar “chrome”, basta con cambiar el “browserName”. Para que funcione con Chrome, tendréis que descargaros el chromeDriver y dejarlo en el mismo directorio que esté el servidor.

Si no estuviéramos usando el modo servidor, podríamos haber usado “webdriver.Chrome” o “webdriver.Firefox”, lo que trataría de acceder directamente, tal y como he terminado haciendo en Java. Me parece que ya es limitar el código, así que he decidido usar la manera genérica, usando “webdriver.Remote”.

Es importante cerrar el driver, ya que si no lo hacemos, el navegador se quedará abierto. Con un único test no es crítico, pero con muchos puede afectar al rendimiento de la máquina.

Y aquí lo dejo. Ahora viene la tarea de buscar en la API aquello que queramos hacer: pulsar botones, ir a enlaces, acceder al DOM,… Pero eso ya os lo dejo a vosotros.

¡Me encanta!

Algunos de vosotros diréis: “¡Esto es la leche! Voy a usarlo para todo”… Pero no es así.

Aunque el sistema es muy potente y permite probar toda la página en distintos navegadores, la ejecución de pruebas es lenta. Abrir un navegador puede llevar varios segundos, incluso estando en caché, lo que hace que todo el proceso vaya lento.

Una solución es usar PhantomJS, que no abre navegadores, pero con esta opción no estaremos probando la web en un navegador real. Para nuestra desgracia, habrá muchas funcionalidades JavaScript que funcionarán de forma distinta dependiendo del navegador… y de PhantomJS.

Así que no es una solución que valga para todo. Sin embargo, sí es interesante para tests de aceptación y para automatizar ciertos procesos. Pero por favor, no lo uséis para probar corner-cases. Para eso existen otro tipo de herramientas más rápidas, como los tests de integración.

En este artículo he usado Selenium/Webdriver en modo Script. Más adelante trataré de mostrarlo para realizar tests.