Selenium con DSL
Selenium es una herramienta para pruebas de aplicaciones web. Quién tuvo la posibilidad de utilizarla, sabrá lo poderosa que es la herramienta, la cuál tiene diversas funciones para ejecutar con nuestra aplicación web. Puede ocurrir, que nuestros test de Selenium se vayan complejizando a medida que nuestra aplicación crece, por lo que esta es una posible solución, combinando el poder de Selenium con un enfoque DSL.
Ejemplo
A continuación mostramos una propuesta de como encarar un test de Selenium con DSL. Para el ejemplo, suponemos una aplicación con seguridad, usuarios con diferentes Roles, y diferentes pantallas:
package com.test;
import static org.junit.Assert.fail;
import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test;
import com.test.selenium.dsl.Usuario;
public class AltaDenunciaSeleniumTest {
@BeforeClass public static void setUpClass() throws Exception { Usuario.inicializar(); }
@AfterClass public static void tearDownClass() throws Exception { Usuario.finalizar(); } @Test public void ingresarConRolAdministrativo_SeDaDeAltaUnaDenuncia() { Usuario.ingresarComoAdministrativo() .irAingresarDenuncia() .completarDenuncia() .aceptar() .verificarFinalizacionSinErrores() .salir(); }
}
De esta forma, escribimos el test de manera que al leer los métodos a los que se invoca, se entiende paso a paso lo que el test realiza, sin confundirnos con la implementación. Utilizando los patrones “method chaining” y “builder” la implementación de la clase Usuario sería una cosa así:
package com.test.selenium.dsl;
import org.openqa.selenium.server.SeleniumServer;
import com.thoughtworks.selenium.DefaultSelenium; import com.thoughtworks.selenium.Selenium; import com.test.selenium.dsl.pagina.HomeAdministrativo;
public class Usuario {
public static final String TIEMPO_ESPERA = "90000"; public static final String VELOCIDAD_CERO = "0"; public static final String VELOCIDAD_TEST = "350"; private static SeleniumServer seleniumServer; private static Selenium selenium ; public static void inicializar() throws Exception { seleniumServer = new SeleniumServer(); seleniumServer.start(); selenium = new DefaultSelenium( "localhost", 4444, "*chrome", "http://localhost:8585/"); selenium.start(); } public static HomeAdministrativo ingresarComoAdministrativo() { Usuario.login("administrativo"); return new HomeAdministrativo(selenium); } public static void finalizar() { selenium.stop(); seleniumServer.stop(); } private static void login(String username) { selenium.setSpeed(VELOCIDAD_TEST); selenium.open(""); selenium.waitForPageToLoad(TIEMPO_ESPERA); if (selenium.isElementPresent("relogin")) { selenium.click("relogin"); selenium.waitForPageToLoad(TIEMPO_ESPERA); } selenium.type("username", username); selenium.click("submitbutton"); selenium.waitForPageToLoad(TIEMPO_ESPERA); selenium.setSpeed(VELOCIDAD_CERO); }
}
Como vemos en el ejemplo, el método ingresarComoAdministrativo instancia y devuelve un objeto de la clase HomeAdministrativo cuya implementación es:
package com.test.selenium.dsl.pagina;
import static org.junit.Assert.assertEquals;
import com.thoughtworks.selenium.Selenium; import com.test.selenium.dsl.Usuario;
public class HomeAdministrativo {
private Selenium selenium; public HomeAdministrativo(Selenium selenium) { this.selenium = selenium; } public AltaDenuncia irAingresarDenuncia() { selenium.setSpeed(Usuario.VELOCIDAD_TEST); selenium.getEval("this.browserbot.getCurrentWindow().selectview('applications')"); selenium.waitForPageToLoad(Usuario.TIEMPO_ESPERA); selenium.click("link=IngresarDenuncia"); selenium.waitForPageToLoad(Usuario.TIEMPO_ESPERA); selenium.setSpeed(Usuario.VELOCIDAD_CERO); return new AltaDenuncia(selenium); } public void salir() { selenium.setSpeed(Usuario.VELOCIDAD_TEST); selenium.getEval("this.browserbot.getCurrentWindow().logoutMethod()"); selenium.waitForPageToLoad(Usuario.TIEMPO_ESPERA); if (selenium.isElementPresent("submit")) { selenium.click("submit"); selenium.waitForPageToLoad(Usuario.TIEMPO_ESPERA); } selenium.setSpeed(Usuario.VELOCIDAD_CERO); }
public HomeAdministrativo verificarFinalizacionSinErrores() { assertEquals("IngresarDenuncia", selenium.getText("link=IngresarDenuncia")); return this; }
}
Volvemos a utilizar el patrón builder y el método ingresar denuncia devuelve un objeto de la clase AltaDenuncia. De esta manera, cada clase representa a una pantalla de la aplicación, y expone cada funcionalidad que la misma ofrece. AltaDenuncia sería así:
package com.test.selenium.dsl.pagina;
import com.thoughtworks.selenium.Selenium; import com.test.selenium.dsl.Usuario;
public class AltaDenuncia {
private Selenium selenium; public AltaDenuncia(Selenium selenium) { this.selenium = selenium; } public AltaDenuncia completarDenuncia() { // Acá iría el código Selenium para completar los campos return this; } public HomeAdministrativo aceptar() { selenium.click("OK"); selenium.waitForPageToLoad(Usuario.TIEMPO_ESPERA); return new HomeAdministrativo(selenium); } public HomeAdministrativo cancelar() { selenium.click("CANCELAR"); selenium.waitForPageToLoad(Usuario.TIEMPO_ESPERA); return new HomeAdministrativo(selenium); }
}