Banear

domingo, 24 de febrero de 2013

Pruebas de Regresión con Selenium y Wicket con Internet Explorer y Firefox

Introducción


Selenium nos permite, entre otras cosas, grabar pruebas realizadas sobre una aplicación web (las acciones que hacemos desde el navegador) para reproducirlas y repetirlas en un futuro sin necesidad de intervención del usuario (o tester).

Ventajas

  • Una vez grabado el caso de prueba, si queremos repetirlo, simplemente lo reproducimos desde Selenium. Si por ejemplo un caso de prueba nos implica hacer 15 clicks por pantallas y tardamos N minutos, si lo grabamos con Selenium, no tendremos que repetir el proceso otra vez mecánicamente como si fuésemos "monos", ya se encarga Selenium de reproducirlo las veces que queramos.
  • Lo podemos utilizar con otros fines. Por ejemplo, para preparar una demostración en la que queremos pasar por N pantallas, para que no se nos olvide nada (o simplemente como guión).
  • Una vez grabados todos los casos de prueba, podemos reproducirlos de golpe para comprobar que tras nuevos cambios que hayamos hecho no se ha estropeado nada (efectos colaterales sobre otras pantallas). Obviamente, habrá que actualizar los casos de prueba (realizando una nueva grabación del caso de prueba o eliminado/insertando pasos) si hemos introducido o eliminado componentes en las pantallas.

Integración de Selenium



El botón de la izquierda es para reproducir los tests y el de la derecha para grabar las interacciones con el navegador (las pruebas que hagamos).
Hacemos un par de clicks sobre la aplicación web con la que estemos trabajando, y grabamos la prueba:

 

Integración de Selenium con Wicket (Consideraciones "especiales")

Si reprodujésemos el test, tendríamos problemas al trabajar con Wicket, ya que si no se especifica en cada componente el MarkupId, Wicket lo autogenera (diferente en cada nueva reproducción de la prueba, por lo que en no encontraría el componente por variar su id en cada plan de ejecución).
Para subsanar este problema, hacemos lo siguiente:
  • En la clase que tengamos que extienda de WebApplication, sobrescribimos el método init, añadiendo la línea getDebugSettings().setOutputComponentPath(true), que nos sirve para habilitar el atributo"wicketpath" (identificador único).

@Override

protected void init() {

   super.init();

   getDebugSettings().setOutputComponentPath(true);

}
  • Creamos una carpeta "wicketPathLocatorBuilder" (Donde queramos, en D: o donde sea
  • Creamos un fichero "user-extension.js.wicketPathLocatorBuilder" con el siguiente contenido, que guardamos en esa carpeta:
 LocatorBuilders.add('wicketpath', function(e) {
        this.log.debug("wicketpath: e=" + e);
        if (e.attributes && e.hasAttribute("wicketpath")) {
            this.log.info("found attribute " + e.getAttribute("wicketpath"));
            return "//" + this.xpathHtmlElement(e.nodeName.toLowerCase()) + "[@wicketpath=" + this.attributeValue(e.getAttribute("wicketpath")) + "]";
        }
        return null;
    });
LocatorBuilders.order.unshift(LocatorBuilders.order.pop());

  • Vamos a Selenium y seleccionamos la opción Options > Options
  • Indicamos la ruta en "Selenium Core extensions"

  • Aceptamos y reiniciamos Firefox
Ya podemos grabar y reproducir nuestras pruebas con Selenium en Wicket sin preocuparnos de que genere ids distintos de cada vez:


Exportando los casos de prueba a scripts

Utilizando "Export Test Case As...":

Podemos exportar los casos de prueba como "scripts" para lanzarlos con Junit, Ruby, C#, ...
Por ejemplo, con Ruby:


Y el script sería este (al ejecutarlo nos abre automáticamente el Firefox, lanza la prueba y cuando acaba se cierra y pone los resultados):

require "selenium-webdriver"
gem "test-unit"
require "test/unit"

class Papidal < Test::Unit::TestCase

  def setup
    @driver = Selenium::WebDriver.for :firefox
    #@base_url = "http://localhost:8090/"
    @accept_next_alert = true
    @driver.manage.timeouts.implicit_wait = 30
    @verification_errors = []
  end
 
  def teardown
    @driver.quit
    assert_equal [], @verification_errors
  end
 
  def test_papidal
    @driver.get("http://localhost:8090/myproject/")
    @driver.find_element(:xpath, "//a[@wicketpath='showModalLink']").click
  end
 
  def element_present?(how, what)
    @driver.find_element(how, what)
    true
  rescue Selenium::WebDriver::Error::NoSuchElementError
    false
  end
 
  def verify(&blk)
    yield
  rescue Test::Unit::AssertionFailedError => ex
    @verification_errors << ex
  end
 
  def close_alert_and_get_its_text(how, what)
    alert = @driver.switch_to().alert()
    if (@accept_next_alert) then
      alert.accept()
    else
      alert.dismiss()
    end
    alert.text
  ensure
    @accept_next_alert = true
  end
end

Si queremos lanzarlo con Internet Explorer, simplemente nos aseguramos que el zoom del navegador esté al 100% (o nos dará un error del estilo "browser zoom level was set to 104%. It should be set to 100%"). Para ello ajustamos el IE pulsando Ctrl+Scroll (menuda frikada :)).

Además, en el caso de ruby con IE, simplemente sería cambiar el Driver, poniendo esta línea:
@driver = Selenium::WebDriver.for :ie

Y añadiendo al PATH (variable de entorno) el fichero: IEDriverServer.exe, que descargaremos de una de estas dos  rutas:
Download version 2.30.2 for (recommended) 32 bit Windows IE or 64 bit Windows IE (http://code.google.com/p/selenium/downloads/detail?name=IEDriverServer_x64_2.30.2.zip)

Como en casa tengo un equipo de 64 bits, me bajé la segunda opción.

El resultado al lanzar el script, sería la apertura automática del IE ejecutando los tests y al acabar se cerraría sólo mostrando por consola esta traza:

Exportando los casos de prueba de Selenium con Junit

Si preferimos exportar el caso de prueba con Junit, para poder lanzarlo cómodamente desde Eclipse, necesitaremos algunas dependencias adicionales. Según el navegador que deseemos usar, modificaremos a nuestro gusto la dependencia "selenium-firefox-driver", en este caso, nos permitirá lanzar nuestros tests contra Firefox:

<dependency>

   <groupId>junit</groupId>

   <artifactId>junit</artifactId>

   <version>4.8.2</version>

</dependency>

<dependency>

      <groupId>org.seleniumhq.selenium</groupId>

      <artifactId>selenium-java</artifactId>

      <version>2.29.1</version>

</dependency>

  

  <dependency>

      <groupId>org.seleniumhq.selenium</groupId>

      <artifactId>selenium-firefox-driver</artifactId>

      <version>2.29.1</version>

</dependency>

Además, para evitar otros errores al ejecutar el test, necesitaremos la siguiente versión de "xml-apis":

<dependency>

     <groupId>xml-apis</groupId>

     <artifactId>xml-apis</artifactId>

     <version>1.4.01</version>

</dependency> 

Selenium, provee los drivers para dar soporte con Safari, IE, Firefox, … Con lo que podemos comprobar si nuestras pruebas funcionan en los distintos navegadores (compatibilidad). En este ejemplo me centro en Firefox, pero en teoría sólo hay que cambiar la clase del driver del navegador que queremos que ejecute el test.

Con JUNIT, con el servidor en local levantado en el puerto 8080, al lanzar el test se abrirá automáticamente el Firefox y en él se ejecutará el caso de prueba (navegando él sólo por las pantallas que le hemos indicado). Al finalizar, si no hubo errores, se cierra el navegador sólo y tendremos el test en "verde".



Para lanzar los Junit contra IE (acordaros de descargar el IEDriverServer.exe):

File file = new File("D:\\util\\IEDriverServer.exe");//El path que sea
System.setProperty("webdriver.ie.driver", file.getAbsolutePath());
driver = new InternetExplorerDriver();

Otras consideraciones

En ocasiones, el "wicketpath" no es suficiente, y para algún elemento puede ser necesario setear los siguientes atributos:

botonFiltro.setMarkupId("filtro1");
botonFiltro.setOutputMarkupId(true);

Se aconseja encarecidamente configurar el orden de los localizadores en el plugin de Selenium de la siguiente forma (según necesidades):



Si es posible que tarde unos segundos una pantalla hasta que se cargue, le damos tiempo a que se cargue la página, con la función isElementPresent. Cuando nos devuelva true, sabemos que ya está cargada la pantalla con el elemento que queremos usar para la prueba. Ejemplo:

//...

driver.findElement(By.xpath("//div[@id='bigPageLinks']/ul/li[3]/form/a")).click();
    for (int second = 0;; second++) {
         if (second >= 60) fail("timeout");
         try { if (isElementPresent(By.cssSelector("#modelo"))) break; } catch (Exception e) {}
         Thread.sleep(1000);
    }

    driver.findElement(By.cssSelector("#modelo")).clear();
    driver.findElement(By.cssSelector("#modelo")).sendKeys("8032");

//...

No hay comentarios:

Publicar un comentario