Introducción a Selenium Grid y Test Paralelos con JUnit

1
15450

Introducción a Selenium Grid y Test Paralelos con JUnit

 

Índice de contenidos.

1. Introducción

Selenium Grid es una herramienta para lanzar test de Selenium de forma distribuida. Utiliza internamente Selenium Remote Control para ejecutar los test de integración con distintos navegadores y plataformas.

Para conocer más sobre Selenium RC podéis consultar el tutorial de Víctor.

Dentro de Selenium Grid se encuentra un módulo importante, el Hub. Este módulo es la parte central de Selenium Grid ya que nos permitirá controlar los distintos Servidores Remote Control encargados de lanzar los test y distribuir los test en los mismos.

Para conocer mucho más sobre Selenium os recomiendo la charla de Victor Madrid. Ver charla

Una vez montada la infraestructura para los test crearemos un test con JUnit 4 y Selenium con la particularidad de que podrán ser lanzados de forma paralela, es decir completamente simultánea en varios hilos. Con esto conseguiremos test de carga con el que poder medir los tiempos de respuesta de nuestro sistema. También conseguiremos distribuir nuestros test de Selenium en varias máquinas y navegadores ganando en eficiencia con test demasiado pesados.

En este tutorial vamos a montar un proyecto con Selenium Grid y test paralelos con JUnit 4.

2. Entorno

  • MacBook Pro 15′ (2.4 GHz Intel Core i5, 4GB DDR3 SDRAM).
  • Sistema Operativo: Mac OS X Snow Leopard 10.6.6
  • Java 1.6.0_24
  • Selenium Grid 1.0.8
  • JUnit 4.8.2

3. Arrancar Selenium Grid

Lo primero será descarganos e instalar Selenium Grid. Nos vamos a su página oficial, descargamos Selenium Grid 1.0.8. Una vez descargado lo descomprimimos y probamos que se ha instalado correctamente (para ello es necesario tener configurado Ant) ejecutando el comando ant sanity-check. Si todo está bien nos aparecerá el siguiente mensaje:

sanity-check:
     [echo] Apache Ant(TM) version 1.8.2 compiled on February 28 2011
     [echo] Java 1.6
     [echo] 
     [echo] ********************************************************************
     [echo] Congratulations, your setup looks good. Have fun with Selenium Grid!
     [echo] ********************************************************************
     [echo] 
     [echo] You can launch a hub by running 'ant launch-hub'
     [echo] You can launch a a remote control with 'ant -Dport=4444 launch-remote-control'

BUILD SUCCESSFUL

La configuración básica de Selenium Grid la podemos editar desde el fichero grid_configuration.yml. En este fichero se definen los valores correspondientes al puerto de escucha de Selenium Grid, cada cuanto tiempo se chequeará el estado de los Remote Controls, el tiempo de espera para que una sesión de test se considere inactiva o bien los distintos entornos donde realizar las pruebas de los test de Selenium. En este último caso se puede configurar el sistema operativo y navegador con el que se lanzará el test, por ejemplo Firefox en Windows o Safari en OS X.

Para arrancar el hub debemos lanzarlo con el comando ‘ant launch-hub’. Una vez arrancado podemos entrar en la consola mediante la url http://localhost:4444/console

Una vez arrancado el Hub debemos arrancar los Remote Control en distintas máquinas encargadas de lanzar los test de Selenium de forma distribuida. En mi entorno de pruebas arrancaré un Remote Control en el Mac OS X Snow Leopard y otro Remote Control en una máquina virtual con Windows XP.

Para arrancar un Remote Control desde la máquina donde se encuentra el Hub arrancado:

	ant launch-remote-control

Para arrancar un Remote Control desde otra máquina hay que arrancar el Remote Control e indicarle la URL de conexión al Hub y el puerto de comunicación:

	ant -Dport=5555 -Dhost=192.168.168.43 -DhubURL=http://192.168.168.36:4444 launch-remote-control

El parámetro port indica el puerto de escucha del Remote Control, el host indica la IP donde se encuentra instalado y el parámetro hubURL indica la IP de nuestro Hub encargado de distribuir los test en los distintos Remote Controls.

Comprobamos si se han conectado los Remote Control al Hub desde la consola anterior:

4. Lanzar los test de Selenium de demo

Con la versión que nos hemos instalado disponemos de unos test de prueba que sirven para comprobar que nuestro sistema está bien configurado. Para lanzarlo tenemos que escribir el comando:

	ant run-demo-in-parallel

Esto levantará el contexto de los test en los dos Remote Controls configurados. Mientras dura este proceso aparecerán en la consola de Selenium Grid los Remote Controls como activos. Los test que vienen están montados con TestNG que tiene un API para dotar de paralelismo a los test. En JUnit 4 están desarrollándolo, de momento están en versión experimental.

5. Lanzar nuestros propios test de Selenium en paralelo

Una vez que hemos configurado nuestro entorno de test y probado la demo que viene en la versión de instalación vamos a montar nuestros propios test.

Lo primero será grabar nuestro test para ello utilizamos Selenium IDE y realizamos una navegación por adictosAlTrabajo. Guardamos el test para JUnit 4. El resultado es el siguiente:

package com.tutoriales.seleniumgrid;

import com.thoughtworks.selenium.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import junit.framework.Assert;

public class AdictosAlTrabajoTestCase {
	
	private Selenium selenium;

	@Before
	public void setUp() throws Exception {
		selenium = new DefaultSelenium("localhost", 4444, "*firefox", "http://www.adictosaltrabajo.com/");
		selenium.start();
	}

	@Test
	public void findTutorial() throws Exception {
		selenium.open("/");
		selenium.type("sbi", "selenium remote control");
		selenium.click("sb");
		selenium.waitForPageToLoad("30000");
		
		Assert.assertEquals("Adictos al Trabajo. Formación y desarrollo | JAVA, JEE, UML, XML |. Tutoriales sobre nuevas tecnologías.", selenium.getTitle());
		selenium.selectFrame("googleSearchFrame");
		selenium.click("//div[@id='res']/div[1]/ol/li[1]/div/h2/a/em");
		selenium.waitForPageToLoad("30000");
	}

	@After
	public void tearDown() throws Exception {
		selenium.stop();
	}
}

Si lanzamos nuestro test de JUnit vemos como se lanza una única instancia que se comunica con uno de los Remote Control. Para poder lanzar varias instancias de un test recurrimos a la clase Parameterized de JUnit que permite levantar varias instancias de test cada una con un parámetro que lo hace diferente al anterior. Este parámetro es recogido de una colección que devuelve un método de la clase de test anotado con @Parameters. El ejemplo del código anterior con esta clase es el siguiente:

package com.tutoriales.seleniumgrid;

import com.thoughtworks.selenium.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

import java.util.Arrays;
import java.util.Collection;

import junit.framework.Assert;

@RunWith(Parameterized.class)
public class AdictosAlTrabajoTestCase {
	
	private Selenium selenium;

	private String browser;

	public AdictosAlTrabajoTestCase(String browser) {
	    this.browser = browser;
	 }
	
	@Parameters
	public static Collection getParameters(){
		return Arrays.asList(new Object[][] { {"*firefox"}, {"*safari"} });
	}
	
	@Before
	public void setUp() throws Exception {
		selenium = new DefaultSelenium("localhost", 4444, this.browser, "http://www.adictosaltrabajo.com/");
		selenium.start();
	}

	@Test
	public void findTutorial() throws Exception {
		selenium.open("/");
		selenium.type("sbi", "selenium remote control");
		selenium.click("sb");
		selenium.waitForPageToLoad("30000");
		
		Assert.assertEquals("Adictos al Trabajo. Formación y desarrollo | JAVA, JEE, UML, XML |. Tutoriales sobre nuevas tecnologías.", selenium.getTitle());
		selenium.selectFrame("googleSearchFrame");
		selenium.click("//div[@id='res']/div[1]/ol/li[1]/div/h2/a/em");
		selenium.waitForPageToLoad("30000");
	}

	@After
	public void tearDown() throws Exception {
		selenium.stop();
	}
}

El método getParameters devolverá un parámetro para cada instancia del test, en este caso hemos escogido dos navegadores para lanzar los test. Para lanzar el Remote Control para safari he ejecutado el comando ant -Denvironment=»*safari» -Dport=5556 launch-remote-control

En este caso se lanzan dos instancias del test pero no de forma paralela, primero una y luego la otra. El hub decide hacia qué Remote Control encamina los trabajos de ejecución del test que siempre se lanzan en el mismo entorno ya que no es necesario un entorno paralelizado debido a que los test son secuenciales. Para conseguir paralelismo y que los test se ejecuten a la vez debemos hacerlo en diferentes hilos. En el siguiente código tomado del blog de Harald Wellmann se declara una clase Parallelized que hereda de Parameterized de JUnit pasándole una clase que implementa un pool de threads donde ejecutarse cada test de forma independiente definido con la clase ThreadPoolScheduler que a su vez implementa RunnerScheduler que permite paralelizar los test.

package com.tutoriales.seleniumgrid;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.junit.runners.Parameterized;
import org.junit.runners.model.RunnerScheduler;

public class Parallelized extends Parameterized {
    
    private static class ThreadPoolScheduler implements RunnerScheduler {
        private ExecutorService executor; 
        
        public ThreadPoolScheduler() {
            String threads = System.getProperty("junit.parallel.threads", "16");
            int numThreads = Integer.parseInt(threads);
            executor = Executors.newFixedThreadPool(numThreads);
        }
        
        public void finished() {
            executor.shutdown();
            try {
                executor.awaitTermination(10, TimeUnit.MINUTES);
            } catch (InterruptedException exc) {
                throw new RuntimeException(exc);
            }
        }

        public void schedule(Runnable childStatement) {
            executor.submit(childStatement);
        }
    }

    public Parallelized(Class klass) throws Throwable {
        super(klass);
        setScheduler(new ThreadPoolScheduler());
    }
}

Si ahora lanzamos los test vemos como se lanzan cada uno en un hilo independiente y todos a la vez. He añadido un nuevo test para ejecutarse en Internet Explorer para eso he arrancado en la máquina virtual un nuevo Remote Control mediante ant -Dport=5557 -Dhost=192.168.168.43 -DhubURL=http://192.168.168.36:4444 -Denvironment=»*iexplore» launch-remote-control

El código del test final es el siguiente:

package com.tutoriales.seleniumgrid;

import com.thoughtworks.selenium.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;

import java.util.Arrays;
import java.util.Collection;

import junit.framework.Assert;

@RunWith(Parallelized.class)
public class AdictosAlTrabajoTestCase {
	
	private Selenium selenium;

	private String browser;

	public AdictosAlTrabajoTestCase(String browser) {
	    this.browser = browser;
	 }
	
	@Parameters
	public static Collection getParameters(){
		return Arrays.asList(new Object[][] { {"*firefox"}, {"*safari"}, {"*iexplore"} });
	}
	
	@Before
	public void setUp() throws Exception {
		selenium = new DefaultSelenium("localhost", 4444, this.browser, "http://www.adictosaltrabajo.com/");
		selenium.start();
	}

	@Test
	public void findTutorial() throws Exception {
		selenium.open("/");
		selenium.type("sbi", "selenium remote control");
		selenium.click("sb");
		selenium.waitForPageToLoad("30000");
		
		Assert.assertEquals("Adictos al Trabajo. Formación y desarrollo | JAVA, JEE, UML, XML |. Tutoriales sobre nuevas tecnologías.", selenium.getTitle());
		selenium.selectFrame("googleSearchFrame");
		selenium.click("//div[@id='res']/div[1]/ol/li[1]/div/h2/a/em");
		selenium.waitForPageToLoad("30000");
	}

	@After
	public void tearDown() throws Exception {
		selenium.stop();
	}
}

El funcionamiento del sistema se ve en la consola de Selenium Grid mientras se están ejecutando los tres test en paralelo


6. Conclusiones

Realizar pruebas exhaustivas de nuestros sistemas es fundamental para asegurar la ausencia de defectos pero también es necesario probar la carga y los tiempos de respuesta del servidor ante peticiones masivas. Con Selenium Grid podemos simular diferentes clientes atacando a nuestro sistema por lo que es una aplicación muy útil y práctica para aumentar la calidad en nuestros desarrollos.

Espero que te haya sido de ayuda.

Un saludo. Juan.

1 COMENTARIO

  1. Estimado Juan Alonso,muy buena tarde, yo también estoy en esto de Selenium, ya hecho algunas pruebas con esta poderosa herramienta, mi pregunta es la siguiente, ¿existe alguna manera dentro de Selenium o mediante código JAVA, para determinar cuando es lanzado el navegador deseado por ejemplo Mozilla Firefox en la versión 36, que se detecte que realmente es la versión deseada, ya que he hecho pruebas con Firefox 36 y me lanza las pruebas con Firefox 39.

    Saludos y mil gracias.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad