Visual Validation con Selenium
por Rúnar Sverrisson, 3/26/2020, 11:20:13 AMPor validación visual nos referimos a la comparación de la interfaz de usuario renderizada con una línea de base dada. En su forma más simple es una comparación píxel a píxel de las capturas de pantalla. Si se detecta cualquier desviación, la prueba fallará. Una forma de hacer este tipo de pruebas automatizadas es utilizando una herramienta llamada Ocular:
Ocular es una simple utilidad que nos ayuda a añadir la función de validación visual en los marcos de automatización de pruebas existentes de WebDriver. Ocular usa Arquillian RushEye para la comparación de imágen.
Setup del proyecto
Vamos a crear una prueba que compruebe las diferencias en la página web de Amazon. Lo usaremos:
- Eclipse
- Maven
- jUnit
- Selenium
- Ocular
Creamos un nuevo proyecto Maven en Eclipse y definimos el pom.xml con las dependencias necesarias:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.orienteed.qa.visual</groupId> <artifactId>VisualValidation</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>VisualValidation</name> <url>https://www.orienteed.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-server</artifactId> <version>3.12.0</version> </dependency> <dependency> <groupId>com.testautomationguru.ocular</groupId> <artifactId>ocular</artifactId> <version>1.0.0.Alpha</version> </dependency> </dependencies> </project>
La estructura del código de prueba es simple y está contenida en una sola clase. Usamos anotaciones jUnit para ejecutar métodos que configurarán Ocular y el WebDriver usado para ejecutar el navegador. En este ejemplo, ejecutamos la prueba en Chrome, así que necesitamos un ChromeDriver. El ChromeDriver funciona como un puente entre Selenio y el navegador Chrome y puede ser encontrado aquí. La ubicación del ejecutable del ChromeDriver debe ser especificada en una variable del sistema. También necesitamos configurar Ocular. Configuramos la ubicación de las imágenes de la línea de base y los resultados y la configuramos para crear una nueva imagen de la línea de base, si no existe una línea de base de antemano. Además, Ocular puede ser instruido para ignorar ciertas partes de la página web. Esto puede ser útil cuando se carga contenido dinámico. En este ejemplo enmascararemos el logo de Amazon (esquina superior derecha) de la pantalla.
package com.orienteed.qa.visual.VisualValidation; import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import org.junit.After; import org.junit.AfterClass; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.Dimension; import org.openqa.selenium.Point; import org.openqa.selenium.UnexpectedAlertBehaviour; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.CapabilityType; import com.testautomationguru.ocular.Ocular; import com.testautomationguru.ocular.comparator.OcularResult; import com.testautomationguru.ocular.sample.SampleBuilder; public class VisualValidation { private final static String OCULAR_SNAPSHOTS = "src/test/resources/blog/snapshots"; private final static String OCULAR_RESULTS = "src/test/resources/blog/results"; private final static String URL = "https://www.amazon.com"; private final static String FIRST_TEST = "FirstTest"; private final static String LOGO = "nav-logo"; private static WebDriver driver; @BeforeClass public static void setup() { Path ocularSnapshotsPath = Paths.get(".", OCULAR_SNAPSHOTS); File ocularSnapshotsDir = new File(ocularSnapshotsPath.toString()); if(!ocularSnapshotsDir.exists()) { ocularSnapshotsDir.mkdirs(); } Path ocularResultsPath = Paths.get(".", OCULAR_RESULTS); File ocularResultsDir = new File(ocularResultsPath.toString()); if(!ocularResultsDir.exists()) { ocularResultsDir.mkdirs(); } Ocular.config() .resultPath(ocularResultsPath) .snapshotPath(ocularSnapshotsPath) .globalSimilarity(50) .saveSnapshot(true); } @Before public void setupDriver() { ChromeOptions options = new ChromeOptions(); options.addArguments("--incognito", "--disable-dev-shm-usage"); options.setCapability(CapabilityType.UNEXPECTED_ALERT_BEHAVIOUR, UnexpectedAlertBehaviour.DISMISS); System.setProperty("webdriver.chrome.driver", "bin/chromedriver_win32/chromedriver.exe"); driver = new ChromeDriver(options); driver.manage().window().setPosition(new Point(0, 0)); driver.manage().window().setSize(new Dimension(1400, 1000)); } public OcularResult compare(String snapshotName, WebElement... elements) { Path snapshotPath = Paths.get(snapshotName + ".png"); SampleBuilder builder = Ocular.snapshot().from(snapshotPath) .sample().using(driver); for (WebElement element : elements) { if (null != element) { builder = builder.excluding(element); } } return builder.compare(); } @Test public void runFirstTest() { driver.get(URL); String snapshotName = FIRST_TEST; WebElement logo = driver.findElement(By.id(LOGO)); OcularResult result = compare(snapshotName, logo); System.out.println(snapshotName + " " + result); Assert.assertTrue(result.isEqualsImages()); } @After public void cleanUp() { driver.close(); } @AfterClass public static void tearDown() throws Exception { driver.quit(); } }
Resultados
Para mostrar la funcionalidad de la prueba, hemos creado una imagen de base ejecutando la prueba una vez y haciendo que Ocular genere una captura de pantalla. Luego hemos editado la captura de pantalla para crear diferencias artificiales que se destacarán en la segunda ejecución. A continuación se muestra la captura de pantalla de la línea de base editada junto con los resultados de la segunda ejecución:
Instantánea de la interfaz de usuario de Amazon.com, utilizada como línea de base. Hemos añadido ciertos elementos a la página.
Resultados de la comparación entre la línea de base y la captura de pantalla actual. Noten las diferencias resaltadas en rojo. Noten también que el logo de la Amazonia ha sido enmascarado.
Ocular genera una imagen de resultado que resalta las diferencias entre la imagen de la línea de base y la captura de pantalla actual. Este resultado está en blanco y negro con las diferencias resaltadas en rojo. El rectángulo azul abarca todas las diferencias que fueron descubiertas. Noten cómo el logo de Amazon está enmascarado por una forma rectangular negra. Una nota lateral interesante es que hay una ligera diferencia en la ubicación de las categorías que aparecen en la parte superior de la página. Esta es una diferencia real entre las dos cargas de la portada de Amazon.
Conclusión
Hemos visto cómo incorporar la Validación Visual en un entorno de pruebas de Selenio QA usando la herramienta Ocular. Esto puede añadir un gran valor al conjunto de pruebas de su equipo y ayudar a detectar discrepancias en la interfaz de usuario que son difíciles de descubrir utilizando el valor tradicional. Concluiremos con algunos consejos y trucos:
- ¿Qué tan estable es el sitio a ser probado? La interfaz de usuario altamente volátil será muy difícil de probar de esta manera.
- Cuando use Ocular, asegúrese de que los niveles de zoom del navegador y del sistema operativo estén ajustados al 100%. De lo contrario, puede experimentar discrepancias al tratar de localizar elementos específicos.
- Durante las pruebas automatizadas con Selenio es importante asegurarse de que un sitio esté completamente cargado antes de ejecutar las pruebas. Por razones obvias, esto es absolutamente crucial para la validación visual.
- Encontrar cada elemento dinámico (identificación del pedido, fecha, anuncio de comercialización, ...) y enmascararlo, ignorándolo efectivamente al comparar las capturas de pantalla.
- Ocular permite establecer un umbral antes de fallar una prueba. Esto puede dar cierta flexibilidad y estabilidad a la ejecución de la prueba.