Marco completo del modelo de objetos de página -2021

En este tutorial, aprenderemos sobre el modelo de objetos de página y también diseñaremos y desarrollaremos el marco del modelo de objetos de página desde cero. 

Habíamos discutido todos los tipos de marco en Selenium, incluido el modelo de objetos de página , aquí lo analizaríamos en profundidad.

Marco del modelo de objetos de página
Desarrollo de marco de modelo de objeto de página

Diseñaremos y desarrollaremos las siguientes características.

¿Qué es el diseño de Page Object Model Framework en Selenium?  

Page Object Model es un modelo de diseño para construir la automatización de pruebas de Selenium, donde distribuimos toda nuestra aplicación bajo prueba en páginas pequeñas (a veces una página web se considera una página y, a veces, una subparte de una página web también se considera una página). Cada una de estas páginas se representa como una clase Java, y las funcionalidades de las páginas se escriben como métodos diferentes en la clase Java de la página respectiva.

Digamos que tiene una aplicación de Gmail que va a automatizar; por lo tanto, la página de inicio de sesión de Gmail es donde tiene algunas funcionalidades importantes, como iniciar sesión, crear una cuenta, etc.

Aquí crearemos una clase java como GmailLoginPage, y escribiremos métodos denominados performLogin (), createUserAccount, etc. 

Digamos que una vez que ha iniciado sesión en su cuenta de Gmail, tiene muchas características como bandeja de entrada, elementos enviados, papelera, etc. Ahora aquí, para cada módulo, crea una clase Java y mantiene sus funcionalidades como métodos Java dentro de las respectivas clases Java. 

Por qué el modelo de objetos de página

Page Object Model es un modelo de diseño de marco muy sólido y avanzado en el que puede encargarse de las siguientes áreas: 

  • Seguridad de la base de código de automatización de las páginas web (las funcionalidades y el código de cada página web no están expuestos a otra página web o clase Java)
  • Reutilizable, es decir, puede llamar al método de página respectivo sin escribirlo en “N” número de lugares en su marco.
  • El localizador de cada una de las páginas reside en diferentes ubicaciones (interfaces de nivel de página o mediante el uso de pagefactory, por lo que en caso de que haya nuevos localizadores para esa página o cambio en el localizador, simplemente puede ir al área de localizadores de página respectiva y cambiarlo, y se reflejará en los métodos de llamada donde se llame a los localizadores)
  • Fácil depuración debido a las características anteriores
  • Fácil mantenimiento.
  • Escalable: puede integrar una amplia gama de herramientas / clientes junto con su marco de modelo de objeto de página y mejorar y escalar su marco de modelo de objeto de página para automatizar también casos de uso supercríticos. 

Estructura del marco del modelo de objetos de página híbrida

En los tutorial anterior, entendimos el modelo de objeto de página híbrido, y ahora diseñaremos y desarrollaremos un marco.

La arquitectura del marco del modelo de objetos de página

Simplemente podemos crear un proyecto maven e incorporar las dependencias en el archivo POM.xml que se requiere para el marco inicialmente que se ve así: 

<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>demo</groupId>
	<artifactId>DemoAutomation</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>DemoAutomation</name>
	<url>http://maven.apache.org</url>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.0</version>
				<configuration>
					<source>7</source>
					<target>7</target>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-surefire-plugin</artifactId>
				<version>2.4.2</version>
				<configuration>
					<suiteXmlFiles>
						<suiteXmlFile>testNg.xml</suiteXmlFile>
					</suiteXmlFiles>
				</configuration>
			</plugin>
		</plugins>
	</build>
	<reporting>
		<plugins>
			<plugin>
				<groupId>org.reportyng</groupId>
				<artifactId>reporty-ng</artifactId>
				<version>1.2</version>
				<configuration>
				    <outputdir>/target/testng-xslt-report</outputdir>
				    <sorttestcaselinks>true</sorttestcaselinks>
			            <testdetailsfilter>FAIL,SKIP,PASS,CONF,BY_CLASS</testdetailsfilter>
				    <showruntimetotals>true</showruntimetotals>
				</configuration>
			</plugin>
		</plugins>
	</reporting>
	<dependencies>
		<dependency>
			<groupId>org.seleniumhq.selenium</groupId>
			<artifactId>selenium-server</artifactId>
			<version>2.53.0</version>
		</dependency>
		<dependency>
			<groupId>org.testng</groupId>
			<artifactId>testng</artifactId>
			<version>6.8.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>3.8</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>3.8</version>
		</dependency>

		<dependency>
			<groupId>com.googlecode.json-simple</groupId>
			<artifactId>json-simple</artifactId>
			<version>1.1</version>
		</dependency>

		<dependency>
			<groupId>net.sourceforge.jexcelapi</groupId>
			<artifactId>jxl</artifactId>
			<version>2.6</version>
		</dependency>
	</dependencies>
</project>

Después de eso, crearemos pequeños módulos y utilidades, donde adjuntamos esta instantánea a continuación solo para proporcionar información / vista de alto nivel. Construiremos los servicios públicos uno por uno. 

Estructura del marco del modelo de objetos de la página de selenio

Aquí están los siguientes módulos que desarrollaremos; hemos proporcionado el fragmento de código para el mismo: 

DriverUtils - Marco del modelo de objetos de página

Este módulo proporciona todas las utilidades y soporte para trabajar con los distintos navegadores (Chrome, Firefox, etc.) Esta utilidad se basa en el patrón de diseño de fábrica, como comentamos en el tutorial anterior aquí.

package com.base.driverUtils;

import org.openqa.selenium.WebDriver;

public interface IDriver {

  public WebDriver init(String browserName);
}

Implementación de Localdriver, que se ejecutará localmente con Selenium Webdriver:

package com.base.driverUtils;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;

public class LocalDriver implements IDriver {

  public WebDriver init(String browserName) {
     switch (browserName) {
     case "firefox":
        return new FirefoxDriver();

     case "chrome":
        System.setProperty("webdriver.chrome.driver",
              "..\\DummyAutomation\\DriverExe\\chromedriver.exe");
        return new ChromeDriver();

     case "ie":
        System.setProperty("webdriver.ie.driver",
              "..\\DummyAutomation\\DriverExe\\IEDriverServer.exe");
        return new InternetExplorerDriver();
     default:
        return new FirefoxDriver();
     }
  }

}

Controlador web remoto: para trabajar con un controlador web remoto (como Selenium Grid), necesita una referencia remota del controlador del navegador, que dice lo siguiente: 

package com.base.driverUtils;

import java.net.MalformedURLException;
import java.net.URL;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;

public class RemoteDriver implements IDriver {

  DesiredCapabilities caps;
  String remoteHuburl;

  @Override
  public WebDriver init(String browserName) {
     switch (browserName) {
     case "firefox":
        try {
           return new RemoteWebDriver(new URL(remoteHuburl), caps.firefox());
        } catch (MalformedURLException e2) {
           // TODO Auto-generated catch block
           e2.printStackTrace();
        }
     case "chrome":
        try {
           return new RemoteWebDriver(new URL(remoteHuburl), caps.chrome());
        } catch (MalformedURLException e1) {
           // TODO Auto-generated catch block
           e1.printStackTrace();
        }
     case "ie":
        try {
           return new RemoteWebDriver(new URL(remoteHuburl), caps.internetExplorer());
        } catch (MalformedURLException e) {
           // TODO Auto-generated catch block
           e.printStackTrace();
        }
     default:
        try {
           return new RemoteWebDriver(new URL(remoteHuburl), caps.firefox());
        } catch (MalformedURLException e) {
           // TODO Auto-generated catch block
           e.printStackTrace();
        }
     }
     return null;
  }
 

}

Clase de controlador de fábrica: Esto nos proporciona el objeto de clase de controlador (remoto / local) para iniciar los navegadores de su elección. Tomaremos el tipo de controlador (local o remoto) y navegador (chrome o firefox etc.) a través del archivo de configuración (hemos usado un archivo de propiedades para mantener las configuraciones, que compartiremos en breve)

package com.base.driverUtils;

public class DriverProvider {

  public IDriver getDriver(String typeOfDriverExecution){
     switch(typeOfDriverExecution){
     case "local":
        return new LocalDriver();
     case "remote":
        return new RemoteDriver();
     default :
        return new LocalDriver();
     }
  }
}

Ahora, siempre que necesite la referencia del controlador, simplemente puede crear el objeto del objeto de clase de fábrica (DriverProvider en este caso) y puede iniciar la instancia del navegador del controlador.

Aquí está el archivo de configuración muy básico; puede crear un archivo de propiedades y almacenar los valores como este: 

modeOfExecution=local
browser=chrome
url=http://www.applicationUrl.com/

Marco del modelo de objetos de DataUtils-Page: 

Hemos diseñado las utilidades de datos aquí con el mismo patrón de diseño de fábrica que hicimos al implementar los módulos del navegador del controlador.

Aquí está el siguiente fragmento de código para el mismo; en el marco, hemos mostrado utilidades de Excel y utilidades de propiedades, puede mejorar más para admitir otras utilidades de datos como YAML, PDF, etc .: 

La interfaz. aquí va así: 

package com.base.dataUtils;

public interface IDataProvider {

  public Object[][] fetchDataSet(String... dataFileInfo);
  public String fetchData(String... dataFileInfo);
}

Aquí está la implementación para Proveedor de datos de Excel

package com.base.dataUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class ExcelDataProvider implements IDataProvider {

  FileInputStream fis = null;
  private static XSSFWorkbook workBook = null;
  private static XSSFCell Cell;
  private static XSSFSheet sheet;

  public static String[][] excelDataSet = null;

  @Override
  public Object[][] fetchDataSet(String... dataFileInfo) {
     String excelFilePath = dataFileInfo[0];
     String excelSheetName = dataFileInfo[1];
     File file = new File(excelFilePath);

     try {
        fis = new FileInputStream(file);
     } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
     }
     try {
        workBook = new XSSFWorkbook(fis);
     } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
     }
     sheet = workBook.getSheet(excelSheetName);
     int ci, cj;
     int rowCount = sheet.getLastRowNum();
     int totalCols = sheet.getRow(0).getPhysicalNumberOfCells();
     excelDataSet = new String[rowCount][totalCols - 1];
     ci = 0;
     for (int i = 1; i <= rowCount; i++, ci++) {
        cj = 0;
        for (int j = 1; j <= totalCols - 1; j++, cj++) {

           try {
              excelDataSet[ci][cj] = getCellData(i, j);
           } catch (Exception e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
           }
        }
     }
     return excelDataSet;

  }

  public static String getCellData(int RowNum, int ColNum) throws Exception {

     try {

        Cell = sheet.getRow(RowNum).getCell(ColNum);

        int dataType = Cell.getCellType();

        if (dataType == 3) {

           return "";

        }

        else if (dataType == XSSFCell.CELL_TYPE_NUMERIC) {
           int i = (int) Cell.getNumericCellValue();
           return Integer.toString(i);
        }

        else {

           String CellData = Cell.getStringCellValue();

           return CellData;

        }
     } catch (Exception e) {

        throw (e);

     }

  }

  @Override
  public String fetchData(String... dataFileInfo) {
     // TODO Auto-generated method stub
     return null;
  }

}

Proveedor de datos de propiedades: 

package com.base.dataUtils;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

public class PropertiesDataProvider implements IDataProvider {

  FileInputStream fis=null;

  @Override
  public Object[][] fetchDataSet(String... dataFileInfo) {
     // TODO Auto-generated method stub
     return null;
  }

  @Override
  public String fetchData(String... dataFileInfo) {

     String dataValue;
     String pathToFile = dataFileInfo[0];
     String key = dataFileInfo[1];
     Properties properties = new Properties();
     try {
        fis=new FileInputStream(pathToFile);
        properties.load(fis);
     } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
     }
     dataValue = properties.getProperty(key);
     return dataValue;
  }

}

La clase de fábrica para estos datos Utilidades

package com.base.dataUtils;

public class DataHelperProvider {

  public IDataProvider getDataHelperProvider(String typeOfDataHandler) {
     switch (typeOfDataHandler) {
     case "excel":
        return new ExcelDataProvider();
     case "properties":
        return new PropertiesDataProvider();
     }
     return null;

  }
}

Utilidades de WebAction -Marco del modelo de objetos de página

En las utilidades, escribimos todas las utilidades relacionadas con sus acciones web como (hacer clic, enviar claves, capturas de pantalla, etc.), y podemos utilizarlas en Métodos de página para realizar acciones web para lograr las funcionalidades de la página como se discutió anteriormente en este tutorial. 

Aquí está el fragmento de código para WebAction Utilities: 

package com.base.webActionHelperUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;


public class WebActionsHelperUtils {

  protected WebDriver driver;

  public WebActionsHelperUtils(WebDriver driver) {

     this.driver = driver;
  }

  public void safeClick(By element) {

     waitForElementToBeClickAble(element, 30);
     driver.findElement(element).click();
  }

  public List<WebElement> getElements(By elements) {
     return driver.findElements(elements);
  }

  public void waitForWebElementsToBeDisplayed(By elements, int timeOuts) {
     WebDriverWait wait = new WebDriverWait(driver, timeOuts);
     wait.until(ExpectedConditions.visibilityOfAllElements(getElements(elements)));
  }

  public void waitForElementToBeClickAble(By element, int timeOutSeconds) {
     WebDriverWait waitForElement = new WebDriverWait(driver, timeOutSeconds);
     waitForElement.until(ExpectedConditions.elementToBeClickable(element));
  }

  public void waitForElementToBeDisplayed(By element, int timeOuts) {
     WebDriverWait wait = new WebDriverWait(driver, timeOuts);
     wait.until(ExpectedConditions.visibilityOfElementLocated(element));
  }

  public void enterTextIntoElement(By element, String textToBeEntered) {
     driver.findElement(element).sendKeys(textToBeEntered);
  }

  public String getText(By element) {
     return driver.findElement(element).getText();

  }

  public String getAttribute(By element, String attribute) {
     return driver.findElement(element).getAttribute(attribute);
  }

  public boolean isSelected(By element) {
     boolean isElementSelected = false;
     if (driver.findElement(element).isSelected() == true) {
        isElementSelected = true;
     }
     return isElementSelected;
  }

  public void clearField(By element) {
     driver.findElement(element).clear();
  }

  public void implicitlyWait(int timeOuts) {
     driver.manage().timeouts().implicitlyWait(timeOuts, TimeUnit.SECONDS);
  }

  public boolean isElementPresent(By element) {
     try {
        driver.findElement(element);
        return true;
     } catch (Exception e) {
        return false;
     }
  }

  public void switchToTab(int indexOfTab) {
     ArrayList<String> tabs = new ArrayList<String>(driver.getWindowHandles());
     driver.switchTo().window(tabs.get(indexOfTab));

  }
}

Page Module utilidades-Page Object Model Framework

Como sabemos, tenemos que crear la clase Page y mantener las funcionalidades de la página en los métodos de la página, así que ahora creemos el Módulo de página para el marco del Modelo de objetos de página: 

Cada clase de página de nuevo extiende las utilidades de WebAction que desarrollamos hace un momento y implementa las interfaces de la página, donde las interfaces de la página no son más que las interfaces para mantener los elementos web / localizadores de la página respectiva.

Ahora, ¿por qué necesitamos interfaces para almacenar los localizadores? 

  • Podríamos usar cualquier archivo de propiedades / excel para mantener los localizadores desde allí, pero en este enfoque, tenemos que buscar los localizadores cada vez que pretendemos usarlos en los métodos de página donde la complejidad del tiempo aumentará, por lo que no almacenamos el localizadores en archivos. 
  • Podríamos usar la misma clase (clase de página con implementación de fábrica de páginas con anotación @findBy), pero no usamos este modelo de objeto de página clásico porque al almacenar los localizadores respectivos en las clases de página respectivas, el código será ilegible y torpe, queríamos separar los localizadores del código para mantener una base de código limpia y la capacidad de mantenimiento, la depuración y la reutilización también aumentarán en este enfoque.
  • Podríamos almacenar los localizadores en clases separadas, pero no lo hicimos porque para llamar “N” clases de localizadores de páginas, tuvimos que crear el número “n” de objetos de los localizadores clasificados; por lo tanto, la complejidad del espacio se verá afectada.

Por lo tanto, usamos interfaces separadas para los localizadores de páginas separados para almacenar según este enfoque; resolvemos todas las declaraciones de problemas anteriores, que son la complejidad del tiempo, la complejidad del espacio y la base de código limpia y mantenible como en las interfaces, no tenemos que crear objetos para acceder a los localizadores.

package com.base.pageModules;

import java.util.List;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import com.base.commonUtils.JSonHandler;
import com.base.webActionHelperUtils.WebActionsHelperUtils;
import com.page.locatorModules.HomePageLocators;

public class HomePage extends WebActionsHelperUtils implements HomePageLocators {

  JSonHandler jsonHandler = new JSonHandler();

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

  public void enterSearchdataToSearchField(String searchData) {

     waitForElementToBeClickAble(SEARCH_BOX, 10);
     enterTextIntoElement(SEARCH_BOX, searchData);

  }

  public void navigatToUrl() {
     driver.get(url);
  }

  public void captureSearchSuggestion(String pathToJsonDataStore, String searchData) {
     List<WebElement> elements = getElements(SUGGESTION_BOX);
     jsonHandler.captureAndWriteJsonData(elements, pathToJsonDataStore, searchData);
  }

  public void genericWait(int timeOuts) {
     implicitlyWait(timeOuts);
  }

  public void clikcOnSelectedElement(String option) {
     int optionSelection = Integer.parseInt(option);
     safeClick(By.xpath("//div[@id='s-separator']/following-sibling::div[" + optionSelection + "]"));
  }

}

Asimismo, puede seguir incluyendo las características de la página en los diferentes métodos de página de la página dentro de las respectivas clases de página. 

Así es como el Interfaces de localizadores de página parece : 

package com.page.locatorModules;

import org.openqa.selenium.By;

public interface HomePageLocators {

 
  By SEARCH_BOX=By.id("twotabsearchtextbox");
  By SUGGESTION_BOX=By.xpath("//div[@id='suggestions']/div");
 
}

Ahora, el siguiente segmento, puede crear un baseSetUp o Basetest donde desea realizar las partes de inicialización / carga de datos. Además, podrías usar @beforeTest, @beoforeClass métodos en esta clase y utilícelos en sus clases de prueba.

BaseSetup La clase se ve así: 

package com.demo.testS;

import org.openqa.selenium.WebDriver;
import org.testng.annotations.DataProvider;

import com.base.dataUtils.DataHelperProvider;
import com.base.dataUtils.IDataProvider;
import com.base.driverUtils.DriverProvider;

public class BaseSetUp {

	public WebDriver driver;
	DriverProvider browserProvider = new DriverProvider();
	DataHelperProvider datahelperProvider = new DataHelperProvider();
	IDataProvider dataProvider = datahelperProvider.getDataHelperProvider("properties");
	IDataProvider dataProviderExcel = datahelperProvider.getDataHelperProvider("excel");
	public final String configProperties = "..\\DummyAutomation\\TestConfigsData\\config.properties";
	public String url = dataProvider.fetchData(configProperties, "url");
	String modeOfExecution = dataProvider.fetchData(configProperties, "modeOfExecution");
	String browserName = dataProvider.fetchData(configProperties, "browser");
	String pathToJasonDataStore = "..\\DummyAutomation\\ProductJsonData\\";
	String pathToExcelData = "..\\DummyAutomation\\TestConfigsData\\TestData.xlsx";

	public WebDriver getDriver() {
		return driver;
	}

	protected void setDriver() {
		driver = browserProvider.getDriver(modeOfExecution).init(browserName);
	}

	@DataProvider(name = "SearchFunctionality")
	public Object[][] getCityDetails() {
		Object[][] arrayObject = dataProviderExcel.fetchDataSet(pathToExcelData, "DataFeed");
		return arrayObject;
	}
}

Clases de prueba: Como estaríamos usando TestNG aquí, debe escribir el método @test para que se desarrolle el script de prueba, como: 

Aquí está el fragmento de código para las clases de prueba  

package com.demo.testS;

import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import com.base.pageModules.HomePage;
import com.base.pageModules.SearchPage;

public class DemoTest extends BaseSetUp {

  HomePage homePage;
  SearchPage searchPage;

  @BeforeMethod
  public void setUpTest() {
     setDriver();
     homePage = new HomePage(driver);
     searchPage = new SearchPage(driver);
     homePage.navigatToUrl();
  }

  @Test(dataProvider = "SearchFunctionality")
  public void search(String searchData, String selectOption) {
     homePage.enterSearchdataToSearchField(searchData);
     homePage.genericWait(5);
     homePage.captureSearchSuggestion(pathToJasonDataStore, searchData);
     homePage.clikcOnSelectedElement(selectOption);
     searchPage.clickOnFirstProduct();
     searchPage.switchToProductSpecificPage();
     searchPage.captureProductData(pathToJasonDataStore, searchData);

  }

  @AfterMethod
  public void tearDown() {
     if (driver != null) {
        driver.quit();
     }
  }

}

Archivo TestNgXML -Marco del modelo de objetos de página

Necesitaría definir una clase XML para testng.xml, que básicamente es un marco de prueba unitario y controla el flujo de su automatización; puedes mencionar las clases de prueba allí mismas.

<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >
<suite name="test-parameter" parallel="tests" thread-count="3">

<test name="DemoAutomation_TarGet">
<classes>
<class name="com.demo.testS.DemoTest"></class>

</classes>
</test>
</suite>

Entonces, con estas actividades, su Modelo de objeto de página marco debería estar listo ahora. Si desea lograr la versión avanzada de su marco, puede incorporar estas áreas a continuación: 

Marco del modelo de objetos de la página de funciones de informes

Puede utilizar cualquier función de informes disponible como atractivo, informe de extensión, informe de TestNG o informe avanzado mediante el uso Pila ELK, etc. 

Solo para mantener la simplicidad, mostramos aquí la función de informes con el informe de extensión, que tiene muchas características y se puede considerar como un nivel intermedio de informes. 

Debe crear una clase para que las utilidades funcionen con el informe de extensión, y mientras lo hace, debe implementar el interfaz ITestlistener de TestNg; el siguiente código muestra cómo: 

package com.cyborg.core.generic.reportUtils;

import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.Status;
import com.aventstack.extentreports.reporter.ExtentHtmlReporter;
import com.cyborg.core.generic.dataUtils.PropertiesDataUtils;

import io.appium.java_client.android.AndroidDriver;

import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.Augmenter;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
import org.testng.Reporter;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;

public class ExtentReportUtils implements ITestListener {

  String screenShotPath = "";

  static ExtentReports extentReports;
  ExtentHtmlReporter extentHtmlReporter;
  protected ExtentTest extentTest;


  static String pathOfFile = "./configurator.properties";
  PropertiesDataUtils propertiesDataUtils = PropertiesDataUtils.getInstance(pathOfFile);
   Boolean log_to_kibana=Boolean.parseBoolean(PropertiesDataUtils.configDataStore.get("log_to_kibana"));
 
   public void setup() {
     try {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
        Date now = new Date();
        String currentTime = simpleDateFormat.format(now);
        extentHtmlReporter = new ExtentHtmlReporter(
              new File(System.getProperty("user.dir") + "_Reports_" + currentTime + ".html"));
        extentHtmlReporter.loadXMLConfig(
              new File(System.getProperty("user.dir") + "/src/test/resources/config/extent-config.xml"));
        extentReports = new ExtentReports();
        extentReports.setSystemInfo("Environment", PropertiesDataUtils.configDataStore.get("Environment"));
        extentReports.setSystemInfo("AppName", PropertiesDataUtils.configDataStore.get("AppName"));
        extentReports.setSystemInfo("ModeOfExecution", PropertiesDataUtils.configDataStore.get("modeOfExecution"));

        extentReports.attachReporter(extentHtmlReporter);
        System.out.println("DONE SETUP FOR extent Report");
     } catch (Exception ex) {
        ex.printStackTrace();
     }
  }

  public void setup(String reportName) {
     extentReports = getExtent(reportName);
  }

  public ExtentReports getExtent(String reportName) {
     if (extentReports != null)
        return extentReports; // avoid creating new instance of html file
     extentReports = new ExtentReports();

     extentReports.attachReporter(getHtmlReporter(reportName));
     return extentReports;
  }

  private ExtentHtmlReporter getHtmlReporter(String reportName) {

     extentHtmlReporter = new ExtentHtmlReporter("./reports/" + reportName + ".html");
     extentHtmlReporter.loadXMLConfig("./src/test/resources/config/extent-config.xml");

     // make the charts visible on report open
     extentHtmlReporter.config().setChartVisibilityOnOpen(true);
     extentHtmlReporter.config().setDocumentTitle(PropertiesDataUtils.configDataStore.get("AppName"));
     extentHtmlReporter.config().setReportName("Regression Cycle");

     // Append the existing report
     extentHtmlReporter.setAppendExisting(false);
     Locale.setDefault(Locale.ENGLISH);
     return extentHtmlReporter;
  }

  public void registerTestMethod(Method method) {
     String testName = method.getName();
     extentTest = extentReports.createTest(testName);

  }

  public void sequenceScreenShot(AndroidDriver driver, String application, String step) {
     try {
        extentTest.addScreenCaptureFromPath(screenshotStepWise(driver, application, step));
     } catch (Exception e) {
        e.printStackTrace();
     }
  }

  public void screenshotAnyCase(ITestResult result, WebDriver driver, String application) {

     String testName = result.getName();
     File file = new File(".");
     String filename = testName + ".png";
     String filepath = null;
     try {
        filepath = file.getCanonicalPath() + "/ScreenShots/" + application + "/" + putLogDate() + filename;
     } catch (IOException e1) {
        e1.printStackTrace();
     }

     if (PropertiesDataUtils.configDataStore.get("run_on_jenkins").equalsIgnoreCase("true"))
        screenShotPath = "job/Cyborg2/" + PropertiesDataUtils.configDataStore.get("build_number")
              + "/artifact/ScreenShots/" + application + "/" + putLogDate() + filename;
     else
        screenShotPath = System.getProperty("user.dir") + "/ScreenShots/" + application + "/" + putLogDate()
              + filename;
     try {
        WebDriver augmentedDriver = new Augmenter().augment(driver);
        File screenshotFile = ((TakesScreenshot) augmentedDriver).getScreenshotAs(OutputType.FILE);
        FileUtils.copyFile(screenshotFile, new File(filepath));
        File reportFile = new File(filepath);
        reportLogScreenshot(reportFile, filename, application);
     } catch (Exception e) {
        Reporter.log("Unable to get the screenshot");
     }
  }

  public String screenshotStepWise(WebDriver driver, String application, String step) throws Exception {

     File file = new File(".");
     String filename = step + ".png";
     String filepath = null;
     try {
        filepath = file.getCanonicalPath() + "/ScreenShots/" + application + "/" + putLogDateWithoutmm() + filename;
     } catch (IOException e1) {
        e1.printStackTrace();
     }

     if (PropertiesDataUtils.configDataStore.get("run_on_jenkins").equalsIgnoreCase("true"))
        screenShotPath = "job/Cyborg2/" + PropertiesDataUtils.configDataStore.get("build_number")
              + "/artifact/ScreenShots/" + application + "/" + putLogDateWithoutmm() + filename;
     else
        screenShotPath = System.getProperty("user.dir") + "/ScreenShots/" + application + "/"
              + putLogDateWithoutmm() + filename;
     try {
        WebDriver augmentedDriver = new Augmenter().augment(driver);
        File screenshotFile = ((TakesScreenshot) augmentedDriver).getScreenshotAs(OutputType.FILE);
        FileUtils.copyFile(screenshotFile, new File(filepath));
     } catch (Exception e) {
        Reporter.log("Unable to get the screenshot");
     }
     return screenShotPath;
  }

  protected void reportLogScreenshot(File file, String fileName, String application) {
     System.setProperty("org.uncommons.reportng.escape-output", "false");
     String absolute = file.getAbsolutePath();
     if (PropertiesDataUtils.configDataStore.get("run_on_jenkins").equalsIgnoreCase("true"))
        absolute = " /job/Cyborg2/" + PropertiesDataUtils.configDataStore.get("build_number")
              + "/artifact/ScreenShots/" + application + "/" + putLogDate() + fileName;
     else
        absolute = System.getProperty("user.dir") + "/ScreenShots/" + application + "/" + putLogDate() + fileName;
     screenShotPath = absolute;

  }

  public void captureStatus(ITestResult result) {
     if (result.getStatus() == ITestResult.SUCCESS) {
        extentTest.log(Status.PASS, "The test method Named as :" + result.getName() + " is PASSED");
        try {
           extentTest.addScreenCaptureFromPath(screenShotPath);
        } catch (IOException e) {

           e.printStackTrace();
        }
     } else if (result.getStatus() == ITestResult.FAILURE) {
        extentTest.log(Status.FAIL, "The test method Named as :" + result.getName() + " is FAILED");
        extentTest.log(Status.FAIL, "The failure : " + result.getThrowable());
        extentTest.log(Status.FAIL, "StackTrace: " + result.getThrowable());
        try {
           extentTest.addScreenCaptureFromPath(screenShotPath);
        } catch (IOException e) {

           e.printStackTrace();
        }
     } else if (result.getStatus() == ITestResult.SKIP) {
        extentTest.log(Status.SKIP, "The test method Named as :" + result.getName() + " is SKIPPED");

     }

  }

  public String putLogDate() {
     Calendar c = new GregorianCalendar();
     c.add(Calendar.DATE, +0);
     Date s = c.getTime();
     String dateString = new SimpleDateFormat("_EEE_ddMMMyyyy_hhmm").format(s);
     return dateString;
  }

  public String putLogDateWithoutmm() {
     Calendar c = new GregorianCalendar();
     c.add(Calendar.DATE, +0);
     Date s = c.getTime();
     String dateString = new SimpleDateFormat("_EEE_ddMMMyyyy_hh").format(s);
     return dateString;
  }

  public void cleanup() {
     extentReports.flush();
  }

  public void onTestStart(ITestResult result) {

     /*
      * try { DateFormat dateFormat = new SimpleDateFormat("yy-MM-dd HH-mm-ss"); Date
      * date = new Date();
      */
     /*
      * record = new ATUTestRecorder(System.getProperty("user.dir")+"/videos",
      * dateFormat.format(date), false); record.start();
      *//*
         *
         * } catch (ATUTestRecorderException e) { e.printStackTrace(); }
         */

  }

  public void onTestSuccess(ITestResult result) {

     /*
      * try { record.stop(); } catch (Exception e) { e.printStackTrace(); }
      */

     String testDescription = result.getMethod().getDescription();
     String testCaseNumber = testDescription.split("_")[0];
     String testDesc = testDescription.split("_")[1];
     String status = "PASSED";
     String exceptionType = "NA";
     String detailedError = "NA";
    
     String data ="{\n" +
           "   \"testCaseNumber\" : \""+testCaseNumber+"\",\n" +
           "   \"status\" : \""+status+"\",\n" +
           "   \"testDescription\" : \""+testDesc+"\",\n" +
           "   \"exceptionType\" : \""+exceptionType+"\",\n" +
           "   \"detailedError\":\""+detailedError+"\"\n" +
           "   \n" +
           "}";

     

  }

  @Override
  public void onTestFailure(ITestResult result) {
    
     String testDescription = result.getMethod().getDescription();
     String testCaseNumber = testDescription.split("_")[0];
     String testDesc = testCaseNumber.split("_")[1];
     String status = "FAILED";
     String exceptionType = String.valueOf(result.getThrowable().getClass().getSimpleName());
     String detailedError = String.valueOf(result.getThrowable().getMessage());
    
     String data ="{\n" +
           "   \"testCaseNumber\" : \""+testCaseNumber+"\",\n" +
           "   \"status\" : \""+status+"\",\n" +
           "   \"testDescription\" : \""+testDesc+"\",\n" +
           "   \"exceptionType\" : \""+exceptionType+"\",\n" +
           "   \"detailedError\":\""+detailedError+"\"\n" +
           "   \n" +
           "}";

    
     // TODO Auto-generated method stub

  }

  @Override
  public void onTestSkipped(ITestResult result) {
     String testDescription = result.getMethod().getDescription();
     String testCaseNumber = testDescription.split("_")[0];
     String testDesc = testCaseNumber.split("_")[1];
     String status = "SKIPPED";
     String exceptionType = result.getThrowable().getClass().getSimpleName();
     String detailedError = result.getThrowable().getMessage();
    
     String data ="{\n" +
           "   \"testCaseNumber\" : \""+testCaseNumber+"\",\n" +
           "   \"status\" : \""+status+"\",\n" +
           "   \"testDescription\" : \""+testDesc+"\",\n" +
           "   \"exceptionType\" : \""+exceptionType+"\",\n" +
           "   \"detailedError\":\""+detailedError+"\"\n" +
           "   \n" +
           "}";

  }

  @Override
  public void onTestFailedButWithinSuccessPercentage(ITestResult result) {
     // TODO Auto-generated method stub

  }

  @Override
  public void onStart(ITestContext context) {
     // TODO Auto-generated method stub

  }

  @Override
  public void onFinish(ITestContext context) {
     // TODO Auto-generated method stub

  }
}

conclusión: Con esto estamos concluyendo el desarrollo del marco del modelo de objeto de página de Selenium a través del cual puede comenzar a construir el marco del modelo de objeto de página y puede llevarlo al nivel avanzado, en la próxima serie del tutorial discutiremos más sobre las características avanzadas del marco de Selenium . Para pasar por la serie de Tutorial de selenio que puede seguir aquí.

Sobre Debarghya

Yo mismo, Debarghya Roy, soy un ARQUITECTO de ingeniería que trabaja con una compañía de Fortune 5 y un colaborador de código abierto, con alrededor de 12 años de experiencia / conocimientos en varias tecnologías.
He trabajado con diversas tecnologías como Java, C #, Python, Groovy, UI Automation (Selenium), Mobile Automation (Appium), API / Backend Automation, Performance Engineering (JMeter, Locust), Security Automation (MobSF, OwAsp, Kali Linux , Astra, ZAP, etc.), RPA, automatización de ingeniería de procesos, automatización de mainframe, desarrollo de back-end con SpringBoot, Kafka, Redis, RabitMQ, ELK stack, GrayLog, Jenkins y también con experiencia en tecnologías de nube, DevOps, etc.
Vivo en Bangalore, India con mi esposa y tengo pasión por los blogs, la música, tocar la guitarra y mi Filosofía de vida es Educación para Todos, que dio origen a LambdaGeeks. Vamos a conectarnos a través de enlaces: https://www.linkedin.com/in/debarghya-roy/

Deja un comentario

Tu dirección de correo electrónico no será publicada.Los campos obligatorios están marcados *

Frikis Lambda