Kompletna struktura modelu obiektów strony -2021

W tym samouczku nauczymy się o modelu obiektów strony, a także zaprojektujemy i opracujemy od podstaw strukturę modelu obiektów strony. 

Omówiliśmy wszystkie typy ram w Selenium, w tym Page Object Model , tutaj omówilibyśmy szczegółowo.

Zaprojektujemy i opracujemy poniższe funkcje.

Co to jest projekt Page Object Model Framework w Selenium  

Model obiektu strony to model projektowy do budowania automatyzacji testów Selenium, w którym dystrybuujemy całą naszą testowaną aplikację na małych stronach (czasem strona internetowa jest uważana za stronę, a czasami podczęść strony internetowej jest również uważana za stronę ). Każda z tych stron jest reprezentowana jako klasa Java, a funkcje stron są zapisywane jako różne metody w klasie Java odpowiedniej strony.

Powiedzmy, że masz aplikację Gmail, którą zautomatyzujesz; stąd strona logowania do Gmaila jest tam, gdzie masz kilka głównych funkcji, takich jak logowanie, tworzenie konta itp.

Tutaj utworzymy klasę java jako GmailLoginPage i napiszemy metody o nazwie performLogin (), createUserAccount itp. 

Powiedzmy, że kiedy jesteś zalogowany na swoje konto Gmail, masz wiele funkcji, takich jak skrzynka odbiorcza, wysłane elementy, kosz itp. Teraz tutaj, dla każdego modułu, tworzysz klasę Java i zachowujesz ich funkcje jako metody Java w odpowiednich klasach java. 

Dlaczego Page Object Model

Page Object Model to bardzo solidny i zaawansowany model projektowania frameworka, w którym możesz zadbać o poniższe obszary: 

Struktura struktury modelu obiektu hybrydowego strony

W w poprzednim samouczku zrozumieliśmy hybrydowy model obiektów strony, a teraz zaprojektujemy i opracujemy framework.

Architektura struktury modelu obiektów strony

Możemy po prostu stworzyć projekt maven i zawrzeć zależności w pliku POM.xml, który jest wymagany dla frameworka, który początkowo wygląda jak ten: 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
\txsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
\t<modelVersion>4.0.0</modelVersion>

\t<groupId>demo</groupId>
\t<artifactId>DemoAutomation</artifactId>
\t<version>0.0.1-SNAPSHOT</version>
\t<packaging>jar</packaging>

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

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

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

Następnie zbudujemy małe moduły i narzędzia, do których dołączyliśmy tę migawkę poniżej, aby zapewnić wgląd / widok na wysokim poziomie. Będziemy budować media pojedynczo. 

Oto poniższe moduły, które będziemy rozwijać; udostępniliśmy fragment kodu dla tego samego: 

DriverUtils - Struktura modelu obiektów strony

Ten moduł zapewnia wszystkie narzędzia i wsparcie do pracy z różnymi przeglądarkami (Chrome, Firefox itp.). To narzędzie jest oparte na Factory wzór projektowy, jak omówiliśmy w poprzednim samouczku tutaj.

pakiet com.base.driverUtils; importuj org.openqa.selenium.WebDriver; publiczny interfejs IDriver { public WebDriver init(String nazwa_przegladarki); }

Implementacja Localdriver, która będzie wykonywana lokalnie za pomocą Webdriver Selenium :

pakiet com.base.driverUtils;
importuj org.openqa.selenium.WebDriver;
importuj org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
klasa publiczna LocalDriver implementuje IDriver {
  public WebDriver init(String nazwaprzeglądarki) {
     przełącznik (nazwa przeglądarki) {
     przypadek „firefoxa”:
        zwróć nowy FirefoxDriver();
     obudowa „chrom”:
        System.setProperty("webdriver.chrome.driver",
              "..\\\\DummyAutomation\\\\DriverExe\\\\chromedriver.exe");
        zwróć nowy ChromeDriver();
     przypadek „tj”:
        System.setProperty("webdriver.ie.driver",
              "..\\\\DummyAutomation\\\\DriverExe\\\\IEDriverServer.exe");
        zwróć nowy sterownik InternetExplorerDriver();
     domyślny:
        zwróć nowy FirefoxDriver();
     }
  }
}

Remote Webdriver: Aby pracować ze zdalnym webdriverem (takim jak Selenium Grid), potrzebujesz zdalnego odniesienia do sterownika przeglądarki, który wygląda następująco: 

pakiet com.base.driverUtils; import java.net.MalformedURLException; importuj java.net.URL; importuj org.openqa.selenium.WebDriver; importuj org.openqa.selenium.remote.DesiredCapabilities; importuj org.openqa.selenium.remote.RemoteWebDriver; klasa publiczna RemoteDriver implementuje IDriver { DesiredCapabilities caps; Ciąg zdalny Huburl; @Override public WebDriver init(String nazwa_przeglądarki) { switch (nazwa_przeglądarki) { case "firefox": spróbuj { return new RemoteWebDriver (nowy URL(remoteHuburl), caps.firefox()); } catch (MalformedURLException e2) { // TODO Automatycznie wygenerowany blok catch e2.printStackTrace(); } case "chrome": spróbuj { return new RemoteWebDriver(new URL(remoteHuburl), caps.chrome()); } catch (MalformedURLException e1) { // TODO Automatycznie wygenerowany blok catch e1.printStackTrace(); } case "ie": try { return new RemoteWebDriver(new URL(remoteHuburl), caps.internetExplorer()); } catch (MalformedURLException e) { // TODO Automatycznie wygenerowany blok catch e.printStackTrace(); } default: try { return new RemoteWebDriver(new URL(remoteHuburl), caps.firefox()); } catch (MalformedURLException e) { // TODO Automatycznie wygenerowany blok catch e.printStackTrace(); } } return null; } }

Klasa sterownika fabrycznego: Zapewnia nam to obiekt klasy sterownika (zdalny / lokalny) do inicjowania wybranych przeglądarek. Przeniesiemy typ sterownika (lokalny lub zdalny) i przeglądarkę (chrome lub firefox itp.) Przez plik konfiguracyjny (użyliśmy pliku właściwości, aby zachować konfiguracje, które wkrótce udostępnimy)

pakiet com.base.driverUtils; public class DriverProvider { public IDriver getDriver(String typeOfDriverExecution){ switch(typeOfDriverExecution){ case "local": return new LocalDriver(); case "remote": zwróć nowy RemoteDriver(); default : zwróć nowy LocalDriver(); } } }

Teraz wszędzie tam, gdzie potrzebujesz odwołania do sterownika, możesz po prostu utworzyć obiekt obiektu klasy fabrycznej (w tym przypadku DriverProvider) i zainicjować instancję przeglądarki sterownika.

Oto bardzo podstawowy plik konfiguracyjny; możesz utworzyć plik właściwości i przechowywać wartości w następujący sposób: 

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

Struktura modelu obiektów strony DataUtils: 

Zaprojektowaliśmy tutaj narzędzia danych jako ten sam wzorzec projektowy Factory, co w przypadku implementacji modułów przeglądarki sterownika.

Oto poniższy fragment kodu dla tego samego; w ramach pokazaliśmy narzędzia Excel i narzędzia właściwości, możesz ulepszyć je bardziej, aby obsługiwać inne narzędzia danych, takie jak YAML, PDF itp .: 

Połączenia Interfejs tutaj wygląda tak: 

pakiet com.base.dataUtils; publiczny interfejs IDataProvider { obiekt publiczny[][] fetchDataSet(String... dataFileInfo); public String fetchData(String... dataFileInfo); }

Oto implementacja dla Dostawca danych programu Excel

pakiet com.base.dataUtils; importuj plik java.io.; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import org.apache.poi.xssf.usermodel.XSSFCell; importuj org.apache.poi.xssf.usermodel.XSSFSheet; importuj org.apache.poi.xssf.usermodel.XSSFWorkbook; klasa publiczna ExcelDataProvider implementuje IDataProvider { fis FileInputStream = null; prywatny statyczny XSSFWorkbook skoroszyt = null; prywatna statyczna komórka XSSFCell; prywatny statyczny arkusz XSSFSheet; public statyczny String[][] excelDataSet = null; @Override public Object[][] fetchDataSet(String... dataFileInfo) { String excelFilePath = dataFileInfo[0]; Ciąg ExcelSheetName = dataFileInfo[1]; Plik pliku = new File(excelFilePath); spróbuj { fis = new FileInputStream(file); } catch (FileNotFoundException e) { // TODO Automatycznie wygenerowany blok catch e.printStackTrace(); } spróbuj { workBook = new XSSFWorkbook(fis); } catch (IOException e) { // TODO Automatycznie wygenerowany blok catch e.printStackTrace(); } arkusz = workBook.getSheet(excelSheetName); int ci, cj; int wierszCount = arkusz.getLastRowNum(); int totalCols = sheet.getRow(0).getPhysicalNumberOfCells(); excelDataSet = new String[rowCount][totalCols - 1]; ci = 0; for (int i = 1; i <= liczba wierszy; i++, ci++) { cj = 0; for (int j = 1; j <= totalCols - 1; j++, cj++) { try { excelDataSet[ci][cj] = getCellData(i, j); } catch (Wyjątek e) { // TODO Automatycznie wygenerowany blok catch e.printStackTrace(); } } } return excelDataSet; } public static String getCellData(int RowNum, int ColNum) wyrzuca wyjątek { try { Cell = sheet.getRow(RowNum).getCell(ColNum); int typ_danych = Cell.getCellType(); if (dataType == 3) { return ""; } else if (dataType == XSSFCell.CELL_TYPE_NUMERIC) { int i = (int) Cell.getNumericCellValue(); return Integer.toString(i); } else { Ciąg CellData = Cell.getStringCellValue(); zwróć CellData; } } catch (Wyjątek e) { throw (e); } } @Override public String fetchData(String... dataFileInfo) { // TODO Automatycznie wygenerowana metoda pośrednicząca return null; } }

Dostawca danych właściwości: 

pakiet com.base.dataUtils; import java.io.FileInputStream; import java.io.IOException; import java.util.Properties; public class PropertiesDataProvider implementuje IDataProvider { FileInputStream fis = null; @Override public Object[][] fetchDataSet(String... dataFileInfo) { // TODO Automatycznie wygenerowana metoda pośrednicząca return null; } @Override public String fetchData(String... dataFileInfo) { String dataValue; String pathToFile = dataFileInfo[0]; Klucz ciągu = dataFileInfo[1]; Właściwości właściwości = nowe Właściwości(); spróbuj { fis=new FileInputStream(pathToFile); properties.load(fis); } catch (IOException e) { // TODO Automatycznie wygenerowany blok catch e.printStackTrace(); } dataValue = properties.getProperty(klucz); zwróć wartość danych; } }

Połączenia Klasa fabryczna dla tych narzędzi danych

pakiet com.base.dataUtils; public class DataHelperProvider { public IDataProvider getDataHelperProvider(String typeOfDataHandler) { switch (typeOfDataHandler) { case "excel": return new ExcelDataProvider(); case "properties": zwróć nowe PropertiesDataProvider(); } zwraca null; } }

Narzędzia WebAction -Struktura obiektowego modelu strony

W narzędziach piszemy wszystkie narzędzia związane z Twoimi działaniami w sieci Web, takie jak (kliknięcie, klawisze wysyłania, zrzuty ekranu itp.), I możemy je wykorzystać w Metodach strony do wykonywania działań internetowych w celu osiągnięcia funkcji strony, jak omówiono wcześniej w tym samouczku. 

Oto fragment kodu dla narzędzi WebAction: 

pakiet com.base.webActionHelperUtils; import java.util.ArrayList; import java.util.Lista; import java.util.concurrent.TimeUnit; import org.openqa.selenium.By; importuj org.openqa.selenium.WebDriver; importuj org.openqa.selenium.WebElement; importuj org.openqa.selenium.support.ui.Oczekiwane warunki; importuj org.openqa.selenium.support.ui.WebDriverWait; public class WebActionsHelperUtils { chroniony sterownik WebDriver; public WebActionsHelperUtils (sterownik WebDriver) { this.driver = sterownik; } public void safeClick(Według elementu) { waitForElementToBeClickAble(element, 30); driver.findElement(element).click(); } lista publiczna getElements(By elements) { return driver.findElements(elements); } public void waitForWebElementsToBeDisplayed(Według elementów, 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(sterownik, timeOutSeconds); waitForElement.until(ExpectedConditions.elementToBeClickable(element)); } public void waitForElementToBeDisplayed(Według elementu, int timeOuts) { WebDriverWait wait = new WebDriverWait(sterownik, 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 atrybut) { return driver.findElement(element).getAttribute(atrybut); } public boolean isSelected(By element) { boolean isElementSelected = false; if (driver.findElement(element).isSelected() == true) { isElementSelected = true; } return isElementSelected; } public void clearField(Według elementu) { driver.findElement(element).clear(); } public void implicitlyWait(int timeOuts) { driver.manage().timeouts().implicitlyWait(timeOuts, TimeUnit.SECONDS); } public boolean isElementPresent(By element) { spróbuj { driver.findElement(element); zwróć prawdę; } catch (wyjątek e) { return false; } } public void switchToTab(int indexOfTab) { ArrayList tabs = nowa ArrayList (sterownik.getWindowHandles()); driver.switchTo().window(tabs.get(indexOfTab)); } }

Narzędzia modułu strony - Struktura modelu obiektów strony

Jak wiemy, musimy utworzyć klasę Page i zachować funkcje strony w metodach strony, więc teraz stwórzmy moduł strony dla struktury Page Object Model: 

Znowu każda klasa stron rozszerza narzędzia WebAction które właśnie opracowaliśmy i implementuje interfejsy Page, gdzie interfejsy stron to nic innego jak interfejsy do przechowywania elementów / lokalizatorów sieci Web odpowiedniej strony.

Teraz dlaczego potrzebujemy interfejsów do przechowywania lokalizatorów: 

W związku z tym użyliśmy oddzielnych interfejsów dla oddzielnych lokalizatorów stron do przechowywania zgodnie z tym podejściem; rozwiązujemy wszystkie powyższe stwierdzenia problemów, które są złożonością czasową, złożonością przestrzeni oraz czystą i możliwą do utrzymania bazą kodu, tak jak w interfejsach, nie musimy tworzyć obiektów, aby uzyskać dostęp do lokalizatorów.

pakiet com.base.pageModules; import java.util.Lista; import org.openqa.selenium.By; importuj org.openqa.selenium.WebDriver; importuj org.openqa.selenium.WebElement; importuj com.base.commonUtils.JSonHandler; importuj com.base.webActionHelperUtils.WebActionsHelperUtils; importuj com.page.locatorModules.HomePageLocators; public class HomePage extends WebActionsHelperUtils implementuje HomePageLocators { JSonHandler jsonHandler = new JSonHandler(); public HomePage (sterownik WebDriver) { super(sterownik); this.driver = kierowca; } 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 elementy = getElements(SUGGESTION_BOX); jsonHandler.captureAndWriteJsonData(elementy, ścieżkaToJsonDataStore, searchData); } public void genericWait(int timeOuts) { implicitlyWait(timeOuts); } public void clikcOnSelectedElement(String opcja) { int optionSelection = Integer.parseInt(opcja); safeClick(By.xpath("//div[@id='s-separator']/following-sibling::div[" + optionSelection + "]")); } }

Podobnie możesz nadal włączać funkcje strony do różnych metod strony w odpowiednich klasach strony. 

Oto jak Interfejsy lokalizatorów stron wygląda jak : 

pakiet com.page.locatorModules; import org.openqa.selenium.By; publiczny interfejs HomePageLocators { By SEARCH_BOX=By.id("twotabsearchtextbox"); By SUGGESTION_BOX=By.xpath("//div[@id='sugestie']/div"); }

Teraz następny segment, możesz utworzyć baseSetUp lub Basetest, w którym chcesz przeprowadzić inicjalizację / ładowanie danych. Możesz także użyć @beforetest, @beoforeclass metod w tej klasie i używaj ich w swoich klasach testowych.

Konfiguracja podstawowa Klasa wygląda następująco: 

pakiet com.demo.testS;
importuj org.openqa.selenium.WebDriver;
import org.testng.annotations.DataProvider;
importuj com.base.dataUtils.DataHelperProvider;
importuj com.base.dataUtils.IDataProvider;
import com.base.driverUtils.DriverProvider;
klasa publiczna BaseSetUp {
\tpubliczny sterownik WebDriver;
\tDostawca sterownikaBrowserProvider = nowy Dostawca sterownika();
\tDataHelperProvider datahelperProvider = nowy DataHelperProvider();
\tIDataProvider dataProvider = datahelperProvider.getDataHelperProvider("właściwości");
\tIDataProvider dataProviderExcel = datahelperProvider.getDataHelperProvider("excel");
\tpublic final String configProperties = "..\\\\DummyAutomation\\\\TestConfigsData\\\\config.properties";
\tpublic String url = dataProvider.fetchData(configProperties, "url");
\tString modeOfExecution = dataProvider.fetchData(configProperties, "modeOfExecution");
\tString nazwaprzeglądarki = dostawca danych.fetchData(configProperties, "przeglądarka");
\tString pathToJasonDataStore = "..\\\\DummyAutomation\\\\ProductJsonData\\\\";
\tString pathToExcelData = "..\\\\DummyAutomation\\\\TestConfigsData\\\\TestData.xlsx";
\tpublic WebDriver getDriver() {
\t\powrót kierowca;
\T}
\tprotected void setDriver() {
\t\tdriver = przeglądarkaProvider.getDriver(modeOfExecution).init(nazwa przeglądarki);
\T}
\t@DataProvider(name = „Funkcja wyszukiwania”)
\tpublic Object[][] getCityDetails() {
\t\tObject[][] arrayObject = dataProviderExcel.fetchDataSet(pathToExcelData, "DataFeed");
\t\treturn obiekt tablicy;
\T}
}

Klasy testowe: Ponieważ używalibyśmy tutaj TestNG, musisz napisać metodę @test, aby skrypt testowy został opracowany, na przykład: 

Oto fragment kodu dla klas testowych  

pakiet com.demo.testS; importuj org.testng.adnotations.AfterMethod; importuj org.testng.adnotations.BeforeMethod; importuj org.testng.adnotacje.Test; importuj com.base.pageModules.HomePage; importuj com.base.pageModules.SearchPage; public class DemoTest rozszerza BaseSetUp { HomePage homePage; Strona wyszukiwania Strona wyszukiwania; @BeforeMethod public void setUpTest() { setDriver(); strona główna = nowa strona główna(sterownik); searchPage = nowa SearchPage(sterownik); strona główna.navigatToUrl(); } @Test(dataProvider = "FunkcjonalnośćWyszukiwania") public void search(String searchData, String selectOption) { homePage.enterSearchdataToSearchField(searchData); homePage.genericWait(5); homePage.captureSearchSuggestion(ścieżkaToJasonDataStore, searchData); strona główna.clikcOnSelectedElement(selectOption); searchPage.clickOnFirstProduct(); searchPage.switchToProductSpecificPage(); searchPage.captureProductData(ścieżkaToJasonDataStore, searchData); } @AfterMethod public void tearDown() { if (driver != null) { driver.quit(); } } }

Plik TestNgXML -Page Object Model Framework

Trzeba by zdefiniować klasę XML dla testng.xml, która jest zasadniczo strukturą testów jednostkowych i kontroluje przepływ automatyzacji; możesz tam wspomnieć o samych klasach testowych.







Tak więc w przypadku tych czynności Twój podstawowy Model obiektu strony Framework powinien być już gotowy. Jeśli chcesz osiągnąć zaawansowaną wersję swojego frameworka, możesz uwzględnić poniższe obszary: 

Raportowanie Struktura modelu obiektowego strony z funkcjami

Możesz użyć dowolnej dostępnej funkcji raportowania, takiej jak urok, raport z zakresu, raport TestNG lub raport z wyprzedzeniem stosując Stos ELK, itd. 

Aby zachować prostotę, pokazujemy tutaj funkcję raportowania z raportem Extent, który ma wiele funkcji wraz z nim i można go uznać za średni poziom raportowania. 

Musisz zbudować klasę, aby mieć narzędzia do pracy z raportem Extent, a robiąc to, musisz zaimplementować interfejs ITestlistener firmy TestNg; poniższy kod pokazuje, jak: 

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 ="{\
" +
           "   \\"testCaseNumber\\" : \\""+testCaseNumber+"\\",\
" +
           "   \\"status\\" : \\""+status+"\\",\
" +
           "   \\"testDescription\\" : \\""+testDesc+"\\",\
" +
           "   \\"exceptionType\\" : \\""+exceptionType+"\\",\
" +
           "   \\"detailedError\\":\\""+detailedError+"\\"\
" +
           "   \
" +
           "}";
     
  }
  @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 ="{\
" +
           "   \\"testCaseNumber\\" : \\""+testCaseNumber+"\\",\
" +
           "   \\"status\\" : \\""+status+"\\",\
" +
           "   \\"testDescription\\" : \\""+testDesc+"\\",\
" +
           "   \\"exceptionType\\" : \\""+exceptionType+"\\",\
" +
           "   \\"detailedError\\":\\""+detailedError+"\\"\
" +
           "   \
" +
           "}";
    
     // 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 ="{\
" +
           "   \\"testCaseNumber\\" : \\""+testCaseNumber+"\\",\
" +
           "   \\"status\\" : \\""+status+"\\",\
" +
           "   \\"testDescription\\" : \\""+testDesc+"\\",\
" +
           "   \\"exceptionType\\" : \\""+exceptionType+"\\",\
" +
           "   \\"detailedError\\":\\""+detailedError+"\\"\
" +
           "   \
" +
           "}";
  }
  @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
  }
}

Wnioski: Na tym kończymy rozwój frameworka Selenium Page Object Model, za pomocą którego możesz rozpocząć budowanie frameworka modelu Page Object i przenieść go na poziom zaawansowany, w nadchodzącej serii samouczków omówimy więcej na temat zaawansowanych funkcji frameworka Selenium . Aby przejść przez serię Samouczek dotyczący selenu, który możesz przejść tutaj.

Zostaw komentarz