¡Compártelo!

Cómo automatizar pruebas con Selenium

Selenium es uno de los frameworks más utilizados para programar y automatizar las interacciones de un usuario sobre una aplicación web. Se puede utilizar a través de lenguajes como Java, Python, C#, Javascript y Kotlin. Es habitual combinarlo con Cucumber para aplicar la metodología BDD simplificando además la estructuración y ejecución de las pruebas. En este post vamos a explicar todas las pautas para automatizar pruebas con Selenium paso a paso.

Entorno

De las distintas configuraciones posibles utilizamos:

Conceptos básicos

Partiendo de un proyecto de Maven se añaden las siguientes dependencias:

También es necesario descargar el WebDriver para el navegador sobre el que queramos ejecutar las pruebas. En este caso se utiliza el Web Driver para Chrome.

Inicializar sesión

Existen distintas posibilidades a la hora de iniciar una sesión con un browser y crear el WebDriver.  Por ejemplo para interactuar con Chrome teniendo el driver correspondiente descargado en una ruta path/to/driver: 

System.setProperty("webdriver.chrome.driver", "path/to/driver");
WebDriver driver = new ChromeDriver();

Sólo se depende del tipo concreto de driver en la instanciación. Las instrucciones al navegador son independientes del tipo de driver y navegador utilizado. 

Navegar a una página web

Con el método get indicar la url a la que se desea navegar:

driver.get("https://rahulshettyacademy.com/seleniumPractise/#/");

Obtener información del browser

Se puede obtener todo tipo de información de la página que acabamos de cargar, por ejemplo, título, url, manejadores de ventana…

String title = driver.getTitle();
String currentUrl = driver.getCurrentUrl();
String windowHandle = driver.getWindowHandle();

Establecer estrategia de espera

Por la naturaleza asíncrona de carga de elementos del DOM es necesario establecer una estrategia de espera en el WebDriver a la hora de buscar algunos elementos. La forma más simple, pero no la más recomendada, es utilizar un wait implícito.

driver.manage().timeouts().implicitlyWait(Duration.ofMillis(500));

Otra posibilidad es emplear wait explícito. En el ejemplo establecemos una espera máxima de dos segundos hasta que el elemento buscado se cargue en el DOM y además su estado sea visible.

WebElement orderBtn = new WebDriverWait(driver, Duration.ofSeconds(2))   .until(ExpectedConditions.visibilityOfElementLocated(       By.xpath("//button[contains(text(),'Place Order')]")));

Existen otras estrategias de espera. Se pueden consultar en la sección waits de la documentación oficial

Buscar elementos

Selenium dispone de métodos para buscar elementos en el DOM. Soporta  selectores basados en clases CSS, identificadores, tipos de tag en DOM y expresiones XPath. Están centralizados en la clase By.

Veamos la forma de recuperar desde java distintos elementos:

automatizar test con Selenium
WebElement input = driver.findElement(By.xpath("//input[@type='search']"));
automatizar test con Selenium
WebElement linkTopDeals = driver.findElement(By.linkText("Top Deals"));
Selenium

WebElement increment = driver.findElement(By.cssSelector("a.increment"));
Selenium

WebElement quantityInput =   driver.findElement(By.xpath("//input[@type='number']"));

Realizar acciones sobre elementos

Cualquier interacción que el usuario pueda hacer con la web se puede realizar mediante el api. Por ejemplo enviar caracteres a un input, hacer click, submit o limpiar cajas de texto. 

Simulamos una búsqueda de con nombre “Broco” y a continuación pulsamos en el icono ‘+’ para incrementar el número de unidades.

searchInput.sendKeys("Broco");
increment.click();

Obtener información de elementos

Queremos comprobar que el número de unidades de “Brócoli” se ha incrementado al pulsar en el icono ‘+’. Para ello obtenemos el valor del atributo value del input correspondiente:

String quantitySelected = quantityInput.getAttribute("value");

Finalizar sesión

Para cerrar el navegador. A partir de esta instrucción no se pueden enviar más comandos al driver.

driver.close();

Integración con JUnit 5

Se utiliza la dependencia:

Un uso típico consiste en utilizar WebDriver dentro de un test unitario para cargar una página y realizar ciertas interacciones con sus elementos. 

Para ilustrar el funcionamiento vamos a unir todos los conceptos que llevamos vistos en el siguiente test.

  • Se navega a la página de compras.
  • Una vez cargada programamos una búsqueda de productos que contengan el texto “Broco”.
  • Para el resultado obtenido pulsamos en el icono ‘+’.
  • Utilizamos aserciones para comprobar que seleccionamos dos productos. También comprobamos el título de la página.
public class SeleniumConceptsTest {

@Test
void testConcepts() {

// Start session
System.setProperty(                             "webdriver.chrome.driver",
Paths.get(System.getProperty("user.dir"),                             "src/test/resources/chromedriver.exe").toString());
WebDriver driver = new ChromeDriver();

// Navigate to web page
driver.get("https://rahulshettyacademy.com/seleniumPractise/#/");

// Request browser information
String title = driver.getTitle();
String currentUrl = driver.getCurrentUrl();
String windowHandle = driver.getWindowHandle();

// Waiting strategy
driver.manage().timeouts().implicitlyWait(Duration.ofMillis(500));

// Finding elements
WebElement searchInput = driver.findElement(                                     By.xpath("//input[@type='search']"));
WebElement linkTopDeals = driver.findElement(By.linkText("Top Deals"));
WebElement increment = driver.findElement(By.cssSelector("a.increment"));
WebElement quantityInput = driver.findElement(                                      By.xpath("//input[@type='number']"));

// Interacting with elements
searchInput.sendKeys("Broco");
increment.click();

// Request element information
String quantitySelected = quantityInput.getAttribute("value");

Assertions.assertEquals(2, Integer.valueOf(quantitySelected));
Assertions.assertEquals("GreenKart - veg and fruits kart", title);

// End session
driver.close();
}
}

Ejecutando el test en el IDE se lanza un browser Chrome donde se van llevando a cabo acciones programadas como se muestra en el vídeo

Además disponemos de los resultados del test:

automatizar test con Selenium

Integración con Cucumber 

Selenium se integra con facilidad con Cucumber. Esto facilita un enfoque BDD de los test, la organización y mantenimiento del código resultante. 

Se precisan la siguientes dependencias:

Construyamos un ejemplo que verifique que los usuarios pueden añadir productos al carrito y acceder a la página de realizar pedido.

El fichero Cart.feature contiene la especificación del escenario de prueba en Gherkin:

# -- FILE: features/Cart.feature
Feature: User experience with Cart

  Scenario Outline: Add product to cart
    Given User is on GreenCart landing page
    When user searched with Shortname <Name> and extracted actual name of product
      And added 4 items of the selected product to cart
    Then verify user has ability to checkout order

  Examples:
  | Name |
  | Cucum  |
  | Carrot  |

Cada línea del fichero se mapea con métodos de java, concepto que se conoce por Step Definitions. La vinculación se realiza mediante anotaciones específicas.

public class LandingPageStepDefinitions {

private TestContextSetup testContextSetup;
private LandingPage landingPage;

public LandingPageStepDefinitions(TestContextSetup testContextSetup) {
this.testContextSetup = testContextSetup;
landingPage = testContextSetup.getPageObjectManager().getLandingPage();
}

@Given("User is on GreenCart landing page")
public void user_is_on_green_cart_landing_page() {
Assertions.assertTrue(landingPage.getTitle().contains("GreenKart"));
}

@When("^user searched with Shortname (.+) and extracted actual name of product$")
public void user_searched_with_shortname_and_extracted_actual_name_of_product(String shortName) {
landingPage.searchItem(shortName);
testContextSetup.setLandingPageProductName(landingPage.getProductName());

}

@When("added {int} items of the selected product to cart")
public void added_items_of_the_selected_product_to_cart(Integer quantity) {
landingPage.incrementQuantity(quantity);
landingPage.addToCart();
}

}
public class CheckoutPageStepDefinitions {

private TestContextSetup testContextSetup;
private CheckoutPage checkoutPage;

public CheckoutPageStepDefinitions(TestContextSetup testContextSetup) {
super();
this.testContextSetup = testContextSetup;
this.checkoutPage = testContextSetup.                   getPageObjectManager().getCheckoutPage();
}

@Then("verify user has ability to checkout order")
public void verify_user_has_ability_to_checkout_order() {
checkoutPage.checkoutItems();
}

}

Una buena práctica de cara al mantenimiento de los test es no incluir el código de Selenium en los StepDefinition. Crear otra clase distinta para mantener los selectores y métodos propios del api de Selenium. 

Lo ponemos en práctica con la clase CheckoutPage. Mantiene los selectores para el icono del carrito y el botón de proceder al checkout. Además implementa un método checkoutItems que interactúa con dichos componentes haciendo click en primer lugar en el icono del carrito y posteriormente en el de checkout.

automatizar test con Selenium
automatizar test con Selenium
public class CheckoutPage {

private static final By CART_BAG = By.cssSelector("[alt='Cart']");
private static final By CHECKOUT_BUTTON = By.xpath("//button[contains(text(),'PROCEED TO CHECKOUT')]");


private WebDriver driver;

public CheckoutPage(WebDriver driver) {
super();
this.driver = driver;
}

public void checkoutItems() {
driver.findElement(CART_BAG).click();
driver.findElement(CHECKOUT_BUTTON).click();
}

}

Ejecutando el escenario se realizan las dos interacciones programadas tal y cómo podemos ver en el vídeo.

En el IDE se comprueba que todos los test han sido correctos.

automatizar test con Selenium

Conclusiones

Hemos visto cómo el API de Selenium permite interactuar con los distintos elementos de una página web. Además utilizando JUnit 5 comprobamos cómo se pueden realizar distintas verificaciones automáticas. Finalmente, vemos una breve introducción de cómo usar Cucumber para estructurar y reutilizar el código de las pruebas hechas con Selenium.  Esperamos que os haya sido útil este artículo para automatizar pruebas con Selenium.

Los ejemplos de este post están accesibles en el repositorio de github

Referencias de interés:

https://www.selenium.dev/

https://cucumber.io/

https://rahulshettyacademy.com/

Artículos relacionados

Descubriendo las posibilidades de los componentes web con Polymer

Descubriendo las posibilidades de los componentes web con Polymer

En este post, exploraremos qué son los Web Components, tecnologías estándar de la web que facilitan la creación de componentes reutilizables y encapsulados. Analizaremos cómo Polymer simplifica su uso y promueve las mejores prácticas de desarrollo, proporcionando herramientas y características que facilitan la construcción de

No code

Qué es el No Code: Principales herramientas

La capacidad de crear soluciones tecnológicas sin la necesidad de escribir código se ha convertido en una tendencia cada vez más relevante. Esto se debe en gran parte al surgimiento de herramientas No Code, que permiten a personas con diversos niveles de habilidad técnica dar

Object Pooling

Patrones de diseño en los videojuegos: Object Pooling

El uso de patrones de diseño, como el Object Pooling, es una práctica muy recomendable cuando se quieren realizar desarrollos de software escalables, robustos y que tengan un buen rendimiento. Además, nos puede ayudar a mantener una estructuración de todo el código fuente para ayudar