page object model with page factory selenium tutorial
In diesem ausführlichen Lernprogramm wird anhand von Beispielen alles über das Page Object Model (POM) mit Pagefactory erläutert. Sie können auch die Implementierung von POM in Selen lernen:
In diesem Tutorial erfahren Sie, wie Sie ein Seitenobjektmodell mithilfe des Page Factory-Ansatzes erstellen. Wir werden uns konzentrieren auf:
- Fabrikklasse
- So erstellen Sie ein einfaches POM mithilfe des Page Factory-Musters
- Verschiedene Anmerkungen, die im Page Factory-Ansatz verwendet werden
Bevor wir sehen, was Pagefactory ist und wie es zusammen mit dem Page-Objektmodell verwendet werden kann, lassen Sie uns verstehen, was Page-Object-Modell ist, das allgemein als POM bekannt ist.
=> Besuchen Sie hier, um die Selenium Training Series For All zu sehen.
Was du lernen wirst:
- Was ist das Seitenobjektmodell (POM)?
- Was ist Pagefactory?
- POM mit Page Factory
- Video-Tutorials - POM mit Page Factory
- Schritte zum Erstellen eines POM mithilfe des Page Factory-Musters
- Seitenebene
- Schritte zum Erstellen eines POM mit einem Echtzeitbeispiel
- Testebene
- Hierarchie der Annotationstypen, die zum Deklarieren von WebElements verwendet wird
- Mehr auf PageFactory.initElements ()
- Häufig gestellte Fragen
- Fazit
Was ist das Seitenobjektmodell (POM)?
Theoretische Terminologien beschreiben die Seitenobjektmodell als Entwurfsmuster zum Erstellen eines Objekt-Repositorys für die in der zu testenden Anwendung verfügbaren Webelemente. Nur wenige andere bezeichnen es als Framework für die Selenium-Automatisierung für die jeweilige zu testende Anwendung.
Was ich jedoch über den Begriff Seitenobjektmodell verstanden habe, ist:
# 1) Es ist ein Entwurfsmuster, bei dem Sie eine separate Java-Klassendatei haben, die jedem Bildschirm oder jeder Seite in der Anwendung entspricht. Die Klassendatei kann das Objekt-Repository der UI-Elemente sowie Methoden enthalten.
#zwei) Wenn sich auf einer Seite riesige Webelemente befinden, kann die Objekt-Repository-Klasse für eine Seite von der Klasse getrennt werden, die Methoden für die entsprechende Seite enthält.
Beispiel: Wenn die Seite 'Konto registrieren' viele Eingabefelder enthält, gibt es möglicherweise eine Klasse 'RegisterAccountObjects.java', die das Objekt-Repository für die Benutzeroberflächenelemente auf der Seite 'Registerkonten' bildet.
Es kann eine separate Klassendatei RegisterAccount.java erstellt werden, die RegisterAccountObjects erweitert oder erbt und alle Methoden enthält, die verschiedene Aktionen auf der Seite ausführen.
#3) Außerdem könnte es ein generisches Paket mit einer {roperties-Datei, Excel-Testdaten und allgemeinen Methoden unter einem Paket geben.
Beispiel: DriverFactory, die auf allen Seiten der Anwendung sehr einfach verwendet werden kann
POM anhand eines Beispiels verstehen
Prüfen Hier um mehr über POM zu erfahren.
Unten finden Sie eine Momentaufnahme der Webseite:
Durch Klicken auf jeden dieser Links wird der Benutzer auf eine neue Seite weitergeleitet.
Hier ist die Momentaufnahme, wie die Projektstruktur mit Selenium unter Verwendung des Page-Objektmodells erstellt wird, das jeder Seite auf der Website entspricht. Jede Java-Klasse enthält ein Objekt-Repository und Methoden zum Ausführen verschiedener Aktionen innerhalb der Seite.
Außerdem wird es eine andere JUNIT oder TestNG oder eine Java-Klassendatei geben, die Aufrufe an Klassendateien dieser Seiten aufruft.
Warum verwenden wir das Seitenobjektmodell?
Die Verwendung dieses leistungsstarken Selenium-Frameworks namens POM oder Seitenobjektmodell ist in aller Munde. Nun stellt sich die Frage: 'Warum POM verwenden?'.
Die einfache Antwort darauf ist, dass POM eine Kombination aus datengesteuerten, modularen und hybriden Frameworks ist. Dies ist ein Ansatz zur systematischen Organisation der Skripte, der es der Qualitätssicherung erleichtert, den Code problemlos zu verwalten, und außerdem dazu beiträgt, redundanten oder doppelten Code zu vermeiden.
Wenn sich beispielsweise der Locator-Wert auf einer bestimmten Seite ändert, ist es sehr einfach, diese schnelle Änderung nur im Skript der jeweiligen Seite zu identifizieren und vorzunehmen, ohne den Code an anderer Stelle zu beeinflussen.
Wir verwenden das Konzept des Seitenobjektmodells in Selenium Webdriver aus folgenden Gründen:
- In diesem POM-Modell wird ein Objekt-Repository erstellt. Es ist unabhängig von Testfällen und kann für ein anderes Projekt wiederverwendet werden.
- Die Namenskonvention von Methoden ist sehr einfach, verständlich und realistischer.
- Unter dem Seitenobjektmodell erstellen wir Seitenklassen, die in einem anderen Projekt wiederverwendet werden können.
- Das Page-Objektmodell ist für das entwickelte Framework aufgrund seiner verschiedenen Vorteile einfach.
- In diesem Modell werden separate Klassen für verschiedene Seiten einer Webanwendung wie Anmeldeseite, Startseite, Mitarbeiterdetailseite, Seite zum Ändern des Kennworts usw. erstellt.
- Wenn sich an einem Element einer Website etwas ändert, müssen wir nur Änderungen in einer Klasse und nicht in allen Klassen vornehmen.
- Das entworfene Skript ist im Ansatz des Seitenobjektmodells wiederverwendbarer, lesbarer und wartbarer.
- Die Projektstruktur ist recht einfach und verständlich.
- Kann PageFactory im Seitenobjektmodell verwenden, um das Webelement zu initialisieren und Elemente im Cache zu speichern.
- TestNG kann auch in den Ansatz des Seitenobjektmodells integriert werden.
Implementierung von einfachem POM in Selen
# 1) Zu automatisierendes Szenario
Jetzt automatisieren wir das gegebene Szenario mithilfe des Seitenobjektmodells.
Das Szenario wird unten erklärt:
Schritt 1: Starten Sie die Site 'https: //demo.vtiger.com'.
Schritt 2: Geben Sie den gültigen Berechtigungsnachweis ein.
Schritt 3: Melden Sie sich auf der Website an.
Schritt 4: Überprüfen Sie die Startseite.
Schritt 5: Melden Sie sich von der Site ab.
Schritt 6: Schließen Sie den Browser.
# 2) Selenskripte für das obige Szenario in POM
Jetzt erstellen wir die POM-Struktur in Eclipse, wie unten erläutert:
Schritt 1: Erstellen Sie ein Projekt in Eclipse - POM-basierte Struktur:
a) Erstellen Sie das Projekt „Seitenobjektmodell“.
b) Erstellen Sie 3 Pakete unter dem Projekt.
- Bibliothek
- Seiten
- Testfälle
Bibliothek: Darunter setzen wir die Codes, die in unseren Testfällen wie Browser-Start, Screenshots usw. immer wieder aufgerufen werden müssen. Der Benutzer kann je nach Projektbedarf weitere Klassen hinzufügen.
Seiten: Darunter werden Klassen für jede Seite in der Webanwendung erstellt und können basierend auf der Anzahl der Seiten in der Anwendung weitere Seitenklassen hinzufügen.
Testfälle: Darunter schreiben wir den Login-Testfall und können nach Bedarf weitere Testfälle hinzufügen, um die gesamte Anwendung zu testen.
c) Klassen unter den Paketen sind in der folgenden Abbildung dargestellt.
Schritt zwei: Erstellen Sie die folgenden Klassen unter dem Bibliothekspaket.
Browser.java: In dieser Klasse werden 3 Browser (Firefox, Chrome und Internet Explorer) definiert, die im Anmeldetestfall aufgerufen werden. Je nach Anforderung kann der Benutzer die Anwendung auch in verschiedenen Browsern testen.
package library; 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 Browser { static WebDriver driver; public static WebDriver StartBrowser(String browsername , String url) { // If the browser is Firefox if (browsername.equalsIgnoreCase('Firefox')) { // Set the path for geckodriver.exe System.setProperty('webdriver.firefox.marionette',' E://Selenium//Selenium_Jars//geckodriver.exe '); driver = new FirefoxDriver(); } // If the browser is Chrome else if (browsername.equalsIgnoreCase('Chrome')) { // Set the path for chromedriver.exe System.setProperty('webdriver.chrome.driver','E://Selenium//Selenium_Jars//chromedriver.exe'); driver = new ChromeDriver(); } // If the browser is IE else if (browsername.equalsIgnoreCase('IE')) { // Set the path for IEdriver.exe System.setProperty('webdriver.ie.driver','E://Selenium//Selenium_Jars//IEDriverServer.exe'); driver = new InternetExplorerDriver(); } driver.manage().window().maximize(); driver.get(url); return driver; } }
ScreenShot.java: In dieser Klasse wird ein Screenshot-Programm geschrieben, das im Testfall aufgerufen wird, wenn der Benutzer einen Screenshot davon erstellen möchte, ob der Test fehlschlägt oder erfolgreich ist.
package library; import java.io.File; import org.apache.commons.io.FileUtils; import org.openqa.selenium.OutputType; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.WebDriver; public class ScreenShot { public static void captureScreenShot(WebDriver driver, String ScreenShotName) { try { File screenshot=((TakesScreenshot)driver).getScreenshotAs(OutputType. FILE ); FileUtils.copyFile(screenshot, new File('E://Selenium//'+ScreenShotName+'.jpg')); } catch (Exception e) { System. out .println(e.getMessage()); e.printStackTrace(); } } }
Schritt 3 : Erstellen Sie Seitenklassen unter Seitenpaket.
HomePage.java: Dies ist die Homepage-Klasse, in der alle Elemente der Homepage und Methoden definiert sind.
package pages; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; public class HomePage { WebDriver driver; By logout = By.id('p_lt_ctl03_wSOB_btnSignOutLink'); By home = By.id('p_lt_ctl02_wCU2_lblLabel'); //Constructor to initialize object public HomePage(WebDriver dr) { this .driver=dr; } public String pageverify() { return driver.findElement(home).getText(); } public void logout() { driver.findElement(logout).click(); } }
LoginPage.java: Dies ist die Anmeldeseitenklasse, in der alle Elemente der Anmeldeseite und Methoden definiert sind.
package pages; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; public class LoginPage { WebDriver driver; By UserID = By.xpath('//*(contains(@id,'Login1_UserName'))'); By password = By.xpath('//*(contains(@id,'Login1_Password'))'); By Submit = By.xpath('//*(contains(@id,'Login1_LoginButton'))'); //Constructor to initialize object public LoginPage(WebDriver driver) { this .driver = driver; } public void loginToSite(String Username, String Password) { this .enterUsername(Username); this .enterPasssword(Password); this .clickSubmit(); } public void enterUsername(String Username) { driver.findElement(UserID).sendKeys(Username); } public void enterPasssword(String Password) { driver.findElement(password).sendKeys(Password); } public void clickSubmit() { driver.findElement(Submit).click(); } }
Schritt 4: Erstellen Sie Testfälle für das Anmeldeszenario.
LoginTestCase.java: Dies ist die LoginTestCase-Klasse, in der der Testfall ausgeführt wird. Der Benutzer kann je nach Projektbedarf auch mehr Testfälle erstellen.
package testcases; import java.util.concurrent.TimeUnit; import library.Browser; import library.ScreenShot; import org.openqa.selenium.WebDriver; import org.testng.Assert; import org.testng.ITestResult; import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; import pages.HomePage; import pages.LoginPage; public class LoginTestCase { WebDriver driver; LoginPage lp; HomePage hp; int i = 0; // Launch of the given browser. @BeforeTest public void browserlaunch() { driver = Browser.StartBrowser('Chrome', 'http://demostore.kenticolab.com/Special-Pages/Logon.aspx'); driver.manage().timeouts().implicitlyWait(30,TimeUnit. SECONDS ); lp = new LoginPage(driver); hp = new HomePage(driver); } // Login to the Site. @Test(priority = 1) public void Login() { lp.loginToSite('gaurav.3n@gmail.com','Test@123'); } // Verifing the Home Page. @Test(priority = 2) public void HomePageVerify() { String HomeText = hp.pageverify(); Assert.assertEquals(HomeText, 'Logged on as'); } // Logout the site. @Test(priority = 3) public void Logout() { hp.logout(); } // Taking Screen shot on test fail @AfterMethod public void screenshot(ITestResult result) { i = i+1; String name = 'ScreenShot'; String x = name+String.valueOf(i); if (ITestResult. FAILURE == result.getStatus()) { ScreenShot.captureScreenShot(driver, x); } } @AfterTest public void closeBrowser() { driver.close(); } }
Schritt 5: Führen Sie „LoginTestCase.java“ aus.
Schritt 6: Ausgabe des Seitenobjektmodells:
- Starten Sie den Chrome-Browser.
- Die Demo-Website wird im Browser geöffnet.
- Melden Sie sich auf der Demo-Site an.
- Überprüfen Sie die Homepage.
- Melden Sie sich von der Site ab.
- Schließen Sie den Browser.
Lassen Sie uns nun das Hauptkonzept dieses Tutorials untersuchen, das die Aufmerksamkeit auf sich zieht, d.h. 'Pagefactory'.
Was ist Pagefactory?
PageFactory ist eine Möglichkeit, das „Seitenobjektmodell“ zu implementieren. Hier folgen wir dem Prinzip der Trennung von Seitenobjekt-Repository und Testmethoden. Es ist ein eingebautes Konzept des Seitenobjektmodells, das sehr optimiert ist.
Lassen Sie uns nun mehr Klarheit über den Begriff Pagefactory haben.
# 1) Erstens bietet das Konzept mit dem Namen Pagefactory eine alternative Möglichkeit in Bezug auf Syntax und Semantik zum Erstellen eines Objekt-Repositorys für die Webelemente auf einer Seite.
#zwei) Zweitens wird eine etwas andere Strategie für die Initialisierung der Webelemente verwendet.
#3) Das Objekt-Repository für die UI-Webelemente kann erstellt werden mit:
- Übliche 'POM ohne Pagefactory' und,
- Alternativ können Sie 'POM with Pagefactory' verwenden.
Nachstehend finden Sie eine bildliche Darstellung derselben:
Jetzt werden wir uns alle Aspekte ansehen, die das übliche POM von POM mit Pagefactory unterscheiden.
a) Der Unterschied in der Syntax beim Auffinden eines Elements unter Verwendung des üblichen POM gegenüber POM mit Pagefactory.
Zum Beispiel , Klicken Hier um das Suchfeld zu finden, das auf der Seite angezeigt wird.
POM ohne Pagefactory:
# 1) Nachfolgend finden Sie, wie Sie das Suchfeld mit dem üblichen POM finden:
WebElement searchNSETxt=driver.findElement(By.id(“searchBox”));
# 2) Der folgende Schritt übergibt den Wert 'Investition' an das Feld 'NSE suchen'.
searchNSETxt.sendkeys(“investment”);
POM mit Pagefactory:
# 1) Sie können das Suchfeld mit Pagefactory wie unten gezeigt suchen.
Die Anmerkung @ FindBy wird in Pagefactory verwendet, um ein Element zu identifizieren, während POM ohne Pagefactory das verwendet driver.findElement () Methode zum Auffinden eines Elements.
Die zweite Aussage für Pagefactory danach @ FindBy weist einen Typ zu WebElement Klasse, die genau wie die Zuweisung eines Elementnamens vom Typ WebElement-Klasse als Rückgabetyp der Methode funktioniert driver.findElement () Dies wird im üblichen POM verwendet (in diesem Beispiel searchNSETxt).
Wir werden uns das ansehen @ FindBy Anmerkungen im Detail im nächsten Teil dieses Tutorials.
@FindBy(id = 'searchBox') WebElement searchNSETxt;
#zwei) Der folgende Schritt übergibt den Wert 'Investition' an das Feld 'Suche NSE' und die Syntax bleibt dieselbe wie die des üblichen POM (POM ohne Pagefactory).
searchNSETxt.sendkeys(“investment”);
b) Der Unterschied in der Strategie der Initialisierung von Webelementen unter Verwendung des üblichen POM gegenüber POM mit Pagefactory.
Verwenden von POM ohne Pagefactory:
Im Folgenden finden Sie ein Code-Snippet zum Festlegen des Chrome-Treiberpfads. Eine WebDriver-Instanz wird mit dem Namenstreiber erstellt und der ChromeDriver wird dem 'Treiber' zugewiesen. Das gleiche Treiberobjekt wird dann verwendet, um die Website der National Stock Exchange zu starten, die Suchbox zu suchen und den Zeichenfolgenwert in das Feld einzugeben.
Der Punkt, den ich hier hervorheben möchte, ist, dass bei POM ohne Seitenfactory die Treiberinstanz zunächst erstellt wird und jedes Webelement jedes Mal neu initialisiert wird, wenn dieses Webelement mit driver.findElement () oder driver aufgerufen wird .findElements ().
Aus diesem Grund wird mit einem neuen Schritt von driver.findElement () für ein Element die DOM-Struktur erneut durchsucht und die Aktualisierung des Elements auf dieser Seite aktualisiert.
System.setProperty('webdriver.chrome.driver', 'C:\eclipse-workspace\automationframework\src\test\java\Drivers\chromedriver.exe'); WebDriver driver = new ChromeDriver(); driver.get('http://www.nseindia.com/'); WebElement searchNSETxt=driver.findElement(By.id(“searchBox”)); searchNSETxt.sendkeys(“investment”);
Verwenden von POM mit Pagefactory:
Neben der Verwendung der Annotation @FindBy anstelle der Methode driver.findElement () wird das folgende Codefragment zusätzlich für Pagefactory verwendet. Die statische initElements () -Methode der PageFactory-Klasse wird verwendet, um alle UI-Elemente auf der Seite zu initialisieren, sobald die Seite geladen wird.
public PagefactoryClass(WebDriver driver) { this.driver = driver; PageFactory.initElements(driver, this); }
Die obige Strategie unterscheidet den PageFactory-Ansatz geringfügig vom üblichen POM. Im üblichen POM muss das Webelement explizit initialisiert werden, während im Pagefactory-Ansatz alle Elemente mit initElements () initialisiert werden, ohne jedes Webelement explizit zu initialisieren.
Zum Beispiel: Wenn das WebElement deklariert, aber nicht im üblichen POM initialisiert wurde, wird der Fehler 'Variable initialisieren' oder die NullPointerException ausgelöst. Daher muss im üblichen POM jedes WebElement explizit initialisiert werden. PageFactory hat in diesem Fall einen Vorteil gegenüber dem üblichen POM.
Lassen Sie uns das Webelement nicht initialisieren BDate (POM ohne Pagefactory) können Sie sehen, dass der Fehler 'Variable initialisieren' angezeigt wird und den Benutzer auffordert, ihn auf null zu initialisieren. Daher können Sie nicht davon ausgehen, dass die Elemente beim Auffinden implizit initialisiert werden.
Element BDate explizit initialisiert (POM ohne Pagefactory):
Schauen wir uns nun einige Instanzen eines vollständigen Programms an, das PageFactory verwendet, um Unklarheiten beim Verständnis des Implementierungsaspekts auszuschließen.
Beispiel 1:
- Gehen Sie zu 'http://www.nseindia.com/'.
- Wählen Sie in der Dropdown-Liste neben dem Suchfeld 'Währungsderivate' aus.
- Suchen Sie nach 'USDINR'. Überprüfen Sie den Text 'US-Dollar-Indische Rupie - USDINR' auf der resultierenden Seite.
Programmstruktur:
- PagefactoryClass.java, das ein Objekt-Repository mit dem Page Factory-Konzept für nseindia.com enthält, das ein Konstruktor zum Initialisieren aller Webelemente ist, wird erstellt. Die Methode selectCurrentDerivative () wählt einen Wert aus dem Dropdown-Feld Suchfeld aus und selectSymbol (), um ein Symbol auf dem auszuwählen Seite, die als nächstes angezeigt wird, und verifytext (), um zu überprüfen, ob der Seitenkopf den Erwartungen entspricht oder nicht.
- NSE_MainClass.java ist die Hauptklassendatei, die alle oben genannten Methoden aufruft und die entsprechenden Aktionen auf der NSE-Site ausführt.
PagefactoryClass.java
package com.pagefactory.knowledge; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; import org.openqa.selenium.support.ui.Select; public class PagefactoryClass { WebDriver driver; @FindBy(id = 'QuoteSearch') WebElement Searchbox; @FindBy(id = 'cidkeyword') WebElement Symbol; @FindBy(id = 'companyName') WebElement pageText; public PagefactoryClass(WebDriver driver) { this.driver = driver; PageFactory.initElements(driver, this); } public void selectCurrentDerivative(String derivative) { Select select = new Select(Searchbox); select.selectByVisibleText(derivative); // 'Currency Derivatives' } public void selectSymbol(String symbol) { Symbol.sendKeys(symbol); } public void verifytext() { if (pageText.getText().equalsIgnoreCase('U S Dollar-Indian Rupee - USDINR')) { System.out.println('Page Header is as expected'); } else System.out.println('Page Header is NOT as expected'); } }
NSE_MainClass.java
package com.pagefactory.knowledge; import java.util.List; import java.util.concurrent.TimeUnit; import org.openqa.selenium.By; import org.openqa.selenium.StaleElementReferenceException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; public class NSE_MainClass { static PagefactoryClass page; static WebDriver driver; public static void main(String() args) { System.setProperty('webdriver.chrome.driver', 'C:\Users\eclipse-workspace\automation-framework\src\test\java\Drivers\chromedriver.exe'); driver = new ChromeDriver(); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); driver.get('https://www.nseindia.com/'); driver.manage().window().maximize(); test_Home_Page_ofNSE(); } public static void test_Home_Page_ofNSE() throws StaleElementReferenceException { page = new PagefactoryClass(driver); page.selectCurrentDerivative('Currency Derivatives'); page.selectSymbol('USD'); List Options = driver.findElements(By.xpath('//span(contains(.,'USD'))')); int count = Options.size(); for (int i = 0; i Beispiel 2:
- Gehen Sie zu 'https://www.shoppersstop.com/brands'.
- Navigieren Sie zum Link Haute Curry.
- Überprüfen Sie, ob die Seite Haute Curry den Text 'Start New Something' enthält.
Programmstruktur
- shopperstopPagefactory.java, das ein Objekt-Repository mit dem pagefactory-Konzept für shoppersstop.com enthält, das ein Konstruktor zum Initialisieren aller Webelemente ist, wird erstellt. Die Methoden closeExtraPopup () behandeln ein sich öffnendes Warn-Popup-Feld. Klicken Sie auf OnHauteCurryLink (), um auf Haute Curry zu klicken Verknüpfen und überprüfen Sie StartNewSomething (), um zu überprüfen, ob die Seite Haute Curry den Text 'Neues starten' enthält.
- Shopperstop_CallPagefactory.java ist die Hauptklassendatei, die alle oben genannten Methoden aufruft und die entsprechenden Aktionen auf der NSE-Site ausführt.
shopperstopPagefactory.java
package com.inportia.automation_framework; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class shopperstopPagefactory { WebDriver driver; @FindBy(id='firstVisit') WebElement extrapopup; @FindBy(xpath='//img(@src='https://sslimages.shoppersstop.com /sys-master/root/haf/h3a/9519787376670/brandMedia_HauteCurry_logo.png')') WebElement HCLink; @FindBy(xpath='/html/body/main/footer/div(1)/p') WebElement Startnew; public shopperstopPagefactory(WebDriver driver) { this.driver=driver; PageFactory.initElements(driver, this); } public void closeExtraPopup() { extrapopup.click(); } public void clickOnHauteCurryLink() { JavascriptExecutor js = (JavascriptExecutor) driver; js.executeScript('arguments(0).click();',HCLink); js.executeAsyncScript('window.setTimeout(arguments(arguments.length - 1), 10000);'); if(driver.getCurrentUrl().equals('https://www.shoppersstop.com/haute-curry')) { System.out.println('We are on the Haute Curry page'); } else { System.out.println('We are NOT on the Haute Curry page'); } } public void verifyStartNewSomething() { if (Startnew.getText().equalsIgnoreCase('Start Something New')) { System.out.println('Start new something text exists'); } else System.out.println('Start new something text DOESNOT exists'); } }
Shopperstop_CallPagefactory.java
package com.inportia.automation_framework; import java.util.concurrent.TimeUnit; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; public class Shopperstop_CallPagefactory extends shopperstopPagefactory { public Shopperstop_CallPagefactory(WebDriver driver) { super(driver); // TODO Auto-generated constructor stub } static WebDriver driver; public static void main(String() args) { System.setProperty('webdriver.chrome.driver', 'C:\eclipse-workspace\automation-framework\src\test\java\Drivers\chromedriver.exe'); driver = new ChromeDriver(); Shopperstop_CallPagefactory s1=new Shopperstop_CallPagefactory(driver); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); driver.get('https://www.shoppersstop.com/brands'); s1.clickOnHauteCurryLink(); s1.verifyStartNewSomething(); } }
POM mit Page Factory
Video-Tutorials - POM mit Page Factory
Teil I.
Teil II
Eine Factory-Klasse wird verwendet, um die Verwendung von Seitenobjekten einfacher und einfacher zu machen.
- Zuerst müssen wir die Webelemente durch Annotation finden @ FindBy in Seitenklassen .
- Initialisieren Sie dann die Elemente mit initElements (), wenn Sie die Seitenklasse instanziieren.
# 1) @FindBy:
Die Annotation @FindBy wird in PageFactory verwendet, um die Webelemente mithilfe verschiedener Locators zu suchen und zu deklarieren.Hier übergeben wir das Attribut sowie seinen Wert, der zum Auffinden des Webelements verwendet wird, an die Annotation @FindBy, und anschließend wird das WebElement deklariert.
Es gibt zwei Möglichkeiten, wie die Anmerkung verwendet werden kann.
Zum Beispiel:
@FindBy(how = How.ID, using='EmailAddress') WebElement Email; @FindBy(id='EmailAddress') WebElement Email;
Ersteres ist jedoch die Standardmethode zum Deklarieren von WebElements.
'Wie' ist eine Klasse und hat statische Variablen wie ID, XPATH, CLASSNAME, LINKTEXT usw.
‘Using’ - Um einer statischen Variablen einen Wert zuzuweisen.
In obigem Beispiel haben wir das Attribut 'id' verwendet, um das Webelement 'Email' zu finden. Ebenso können wir die folgenden Locators mit den @ FindBy-Annotationen verwenden:
- Klassenname
- CSS
- Name
- xpath
- Verlinke den Namen
- Link Text
- PartialLinkText
# 2) initElements ():
Die initElements sind eine statische Methode der PageFactory-Klasse, mit der alle durch die @ FindBy-Annotation gefundenen Webelemente initialisiert werden. Somit können die Page-Klassen leicht instanziiert werden.
initElements(WebDriver driver, java.lang.Class pageObjectClass)
Wir sollten auch verstehen, dass POM den OOPS-Prinzipien folgt.
- WebElements werden als private Mitgliedsvariablen deklariert (Data Hiding).
- WebElements mit entsprechenden Methoden binden (Encapsulation).
Schritte zum Erstellen eines POM mithilfe des Page Factory-Musters
# 1) Erstellen Sie für jede Webseite eine separate Java-Klassendatei.
#zwei) In jeder Klasse sollten alle WebElements als Variablen deklariert werden (mit annotation - @FindBy) und mit der Methode initElement () initialisiert werden. Deklarierte WebElements müssen initialisiert werden, um in den Aktionsmethoden verwendet zu werden.
#3) Definieren Sie entsprechende Methoden, die auf diese Variablen einwirken.
Nehmen wir ein Beispiel für ein einfaches Szenario:
- Öffnen Sie die URL einer Anwendung.
- Geben Sie E-Mail-Adresse und Passwort ein.
- Klicken Sie auf die Schaltfläche Anmelden.
- Überprüfen Sie die erfolgreiche Anmeldemeldung auf der Suchseite.
Seitenebene
Hier haben wir 2 Seiten,
- Startseite - Die Seite, die geöffnet wird, wenn die URL eingegeben wird und auf der wir die Daten für die Anmeldung eingeben.
- SearchPage - Eine Seite, die nach erfolgreicher Anmeldung angezeigt wird.
In der Seitenebene wird jede Seite in der Webanwendung als separate Java-Klasse deklariert, und ihre Locators und Aktionen werden dort erwähnt.
Schritte zum Erstellen eines POM mit einem Echtzeitbeispiel
# 1) Erstellen Sie eine Java-Klasse für jede Seite:
In diesem Beispiel Wir werden auf 2 Webseiten zugreifen, 'Home' - und 'Search' -Seiten.
Daher erstellen wir 2 Java-Klassen in Page Layer (oder in einem Paket, z. B. com.automation.pages).
Package Name :com.automation.pages HomePage.java SearchPage.java
# 2) Definieren Sie WebElements als Variablen mit Annotation @FindBy:
Wir würden interagieren mit:
- Feld E-Mail, Passwort, Anmeldeschaltfläche auf der Startseite.
- Erfolgreiche Nachricht auf der Suchseite.
Also werden wir WebElements mit @FindBy definieren
Zum Beispiel: Wenn wir die EmailAddress anhand der Attribut-ID identifizieren wollen, lautet ihre Variablendeklaration
//Locator for EmailId field @FindBy(how=How.ID,using='EmailId') private WebElementEmailIdAddress;
# 3) Erstellen Sie Methoden für Aktionen, die in WebElements ausgeführt werden.
Die folgenden Aktionen werden in WebElements ausgeführt:
- Geben Sie action in das Feld E-Mail-Adresse ein.
- Geben Sie action in das Feld Passwort ein.
- Klicken Sie auf die Schaltfläche Anmelden.
Zum Beispiel, Benutzerdefinierte Methoden werden für jede Aktion im WebElement wie folgt erstellt:
public void typeEmailId(String Id){ driver.findElement(EmailAddress).sendKeys(Id) }
Hier wird die ID als Parameter in der Methode übergeben, da die Eingabe vom Benutzer aus dem Haupttestfall gesendet wird.
Hinweis ::In jeder Klasse der Seitenschicht muss ein Konstruktor erstellt werden, um die Treiberinstanz von der Hauptklasse in der Testschicht abzurufen und WebElements (Seitenobjekte), die in der Seitenklasse deklariert sind, mit PageFactory.InitElement () zu initialisieren. .
Wir initiieren den Treiber hier nicht, sondern seine Instanz wird von der Hauptklasse empfangen, wenn das Objekt der Page Layer-Klasse erstellt wird.
InitElement () - wird verwendet, um die deklarierten WebElements mithilfe der Treiberinstanz aus der Hauptklasse zu initialisieren. Mit anderen Worten, WebElements werden mithilfe der Treiberinstanz erstellt. Erst nachdem die WebElements initialisiert wurden, können sie in den Methoden zum Ausführen von Aktionen verwendet werden.
Für jede Seite werden zwei Java-Klassen erstellt, wie unten gezeigt:
HomePage.java
//package com.automation.pages; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; public class HomePage { WebDriver driver; // Locator for Email Address @FindBy(how=How.ID,using='EmailId') private WebElement EmailIdAddress; // Locator for Password field @FindBy(how=How.ID,using='Password ') private WebElement Password; // Locator for SignIn Button @FindBy(how=How.ID,using='SignInButton') private WebElement SignInButton; // Method to type EmailId public void typeEmailId(String Id){ driver.findElement(EmailAddress).sendKeys(Id) } // Method to type Password public void typePassword(String PasswordValue){ driver.findElement(Password).sendKeys(PasswordValue) } // Method to click SignIn Button public void clickSignIn(){ driver.findElement(SignInButton).click() } // Constructor // Gets called when object of this page is created in MainClass.java public HomePage(WebDriver driver) { // 'this' keyword is used here to distinguish global and local variable 'driver' //gets driver as parameter from MainClass.java and assigns to the driver instance in this class this.driver=driver; PageFactory.initElements(driver,this); // Initialises WebElements declared in this class using driver instance. } }
SearchPage.Java
//package com.automation.pages; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; public class SearchPage{ WebDriver driver; // Locator for Success Message @FindBy(how=How.ID,using='Message') private WebElement SuccessMessage; // Method that return True or False depending on whether the message is displayed public Boolean MessageDisplayed(){ Boolean status = driver.findElement(SuccessMessage).isDisplayed(); return status; } // Constructor // This constructor is invoked when object of this page is created in MainClass.java public SearchPage(WebDriver driver) { // 'this' keyword is used here to distinguish global and local variable 'driver' //gets driver as parameter from MainClass.java and assigns to the driver instance in this class this.driver=driver; PageFactory.initElements(driver,this); // Initialises WebElements declared in this class using driver instance. } }
Testebene
In dieser Klasse sind Testfälle implementiert. Wir erstellen ein separates Paket, beispielsweise com.automation.test, und erstellen dann hier eine Java-Klasse (MainClass.java).
Schritte zum Erstellen von Testfällen:
- Initialisieren Sie den Treiber und öffnen Sie die Anwendung.
- Erstellen Sie ein Objekt der PageLayer-Klasse (für jede Webseite) und übergeben Sie die Treiberinstanz als Parameter.
- Rufen Sie mit dem erstellten Objekt die Methoden in der PageLayer-Klasse (für jede Webseite) auf, um Aktionen / Überprüfungen durchzuführen.
- Wiederholen Sie Schritt 3, bis alle Aktionen ausgeführt wurden, und schließen Sie dann den Treiber.
//package com.automation.test; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; public class MainClass { public static void main(String() args) { System.setProperty('webdriver.chrome.driver','./exefiles/chromedriver.exe'); WebDriver driver= new ChromeDriver(); driver.manage().window().maximize(); driver.get('URL mentioned here'); // Creating object of HomePage and driver instance is passed as parameter to constructor of Homepage.Java HomePage homePage= new HomePage(driver); // Type EmailAddress homePage.typeEmailId('abc@ymail.com'); // EmailId value is passed as paramter which in turn will be assigned to the method in HomePage.Java // Type Password Value homePage.typePassword('password123'); // Password value is passed as paramter which in turn will be assigned to the method in HomePage.Java // Click on SignIn Button homePage.clickSignIn(); // Creating an object of LoginPage and driver instance is passed as parameter to constructor of SearchPage.Java SearchPage searchPage= new SearchPage(driver); //Verify that Success Message is displayed Assert.assertTrue(searchPage.MessageDisplayed()); //Quit browser driver.quit(); } }
Hierarchie der Annotationstypen, die zum Deklarieren von WebElements verwendet wird
Mit Hilfe von Anmerkungen können Sie eine Standortstrategie für die UI-Elemente erstellen.
# 1) @FindBy
Wenn es um Pagefactory geht, fungiert @FindBy als Zauberstab. Es fügt dem Konzept die ganze Kraft hinzu. Sie wissen jetzt, dass die @ FindBy-Annotation in Pagefactory dieselbe Leistung wie die von driver.findElement () im üblichen Seitenobjektmodell aufweist. Es wird verwendet, um WebElement / WebElements zu finden mit einem Kriterium .
# 2) @FindBys
Es wird verwendet, um WebElement mit zu finden mehr als ein Kriterium und müssen alle angegebenen Kriterien erfüllen. Diese Kriterien sollten in einer Eltern-Kind-Beziehung erwähnt werden. Mit anderen Worten, dies verwendet eine UND-bedingte Beziehung, um die WebElements anhand der angegebenen Kriterien zu lokalisieren. Es verwendet mehrere @FindBy, um jedes Kriterium zu definieren.
Zum Beispiel:
HTML-Quellcode eines WebElement:
In POM:
@FindBys({ @FindBy(id = 'searchId_1'), @FindBy(name = 'search_field') }) WebElementSearchButton;
Im obigen Beispiel befindet sich das WebElement 'SearchButton' nur, wenn es vorhanden ist passt zu beiden Die Kriterien, deren ID-Wert 'searchId_1' und deren Namenswert 'search_field' ist. Bitte beachten Sie, dass die ersten Kriterien zu einem übergeordneten Tag und die zweiten Kriterien zu einem untergeordneten Tag gehören.
# 3) @FindAll
Es wird verwendet, um WebElement mit zu finden mehr als ein Kriterium und es muss mindestens einem der angegebenen Kriterien entsprechen. Dies verwendet ODER-bedingte Beziehungen, um WebElements zu finden. Es verwendet mehrere @FindBy, um alle Kriterien zu definieren.
Zum Beispiel:
HTML SourceCode:
In POM:
@FindBys({ @FindBy(id = 'UsernameNameField_1'), // doesn’t match @FindBy(name = 'User_Id') //matches @FindBy(className = “UserName_r”) //matches }) WebElementUserName;
Im obigen Beispiel befindet sich der WebElement-Benutzername, wenn er vorhanden ist passt zu mindestens einem der genannten Kriterien.
# 4) @CacheLookUp
Wenn das WebElement in Testfällen häufiger verwendet wird, sucht Selenium jedes Mal nach dem WebElement, wenn das Testskript ausgeführt wird. In den Fällen, in denen bestimmte WebElements global für alle TC verwendet werden ( Zum Beispiel, Das Anmeldeszenario tritt für jeden TC auf. Diese Annotation kann verwendet werden, um diese WebElements nach dem ersten Lesen im Cache-Speicher zu halten.
Dies wiederum hilft dem Code, schneller ausgeführt zu werden, da er nicht jedes Mal nach dem WebElement auf der Seite suchen muss, sondern seine Referenz aus dem Speicher abrufen kann.
Dies kann ein Präfix für @FindBy, @FindBys und @FindAll sein.
Zum Beispiel:
@CacheLookUp @FindBys({ @FindBy(id = 'UsernameNameField_1'), @FindBy(name = 'User_Id') @FindBy(className = “UserName_r”) }) WebElementUserName;
Beachten Sie außerdem, dass diese Anmerkung nur für WebElements verwendet werden sollte, deren Attributwert (wie xpath, id name, class name usw.) sich nicht häufig ändert. Sobald das WebElement zum ersten Mal gefunden wurde, behält es seine Referenz im Cache-Speicher bei.
Wenn sich das Attribut von WebElement nach einigen Tagen ändert, kann Selenium das Element nicht finden, da es bereits seine alte Referenz im Cache-Speicher hat und die jüngste Änderung in WebElement nicht berücksichtigt.
Mehr auf PageFactory.initElements ()
Nachdem wir die Strategie von Pagefactory zum Initialisieren der Webelemente mit InitElements () verstanden haben, versuchen wir, die verschiedenen Versionen der Methode zu verstehen.
Die uns bekannte Methode verwendet das Treiberobjekt und das aktuelle Klassenobjekt als Eingabeparameter und gibt das Seitenobjekt zurück, indem alle Elemente auf der Seite implizit und proaktiv initialisiert werden.
In der Praxis ist die Verwendung des Konstruktors, wie im obigen Abschnitt gezeigt, den anderen Verwendungsarten vorzuziehen.
Alternative Möglichkeiten, die Methode aufzurufen, sind:
# 1) Anstatt den Zeiger 'this' zu verwenden, können Sie das aktuelle Klassenobjekt erstellen, die Treiberinstanz an dieses übergeben und die statische Methode initElements mit Parametern aufrufen, d. H. Dem Treiberobjekt und dem gerade erstellten Klassenobjekt.
public PagefactoryClass(WebDriver driver) { //version 2 PagefactoryClass page=new PagefactoryClass(driver); PageFactory.initElements(driver, page); }
#zwei) Die dritte Möglichkeit, Elemente mithilfe der Pagefactory-Klasse zu initialisieren, ist die Verwendung der API „Reflection“. Ja, anstatt ein Klassenobjekt mit einem 'neuen' Schlüsselwort zu erstellen, kann classname.class als Teil des Eingabeparameters initElements () übergeben werden.
public PagefactoryClass(WebDriver driver) { //version 3 PagefactoryClass page=PageFactory.initElements(driver, PagefactoryClass.class); }
Häufig gestellte Fragen
F # 1) Welche unterschiedlichen Locator-Strategien werden für @FindBy verwendet?
Antworten: Die einfache Antwort darauf lautet, dass für @FindBy keine unterschiedlichen Locator-Strategien verwendet werden.
Sie verwenden dieselben 8 Locator-Strategien, die die findElement () -Methode im üblichen POM verwendet:
- Ich würde
- Name
- Klassenname
- xpath
- CSS
- Verlinke den Namen
- Link Text
- PartialLinkText
F # 2) Gibt es auch verschiedene Versionen für die Verwendung von @ FindBy-Anmerkungen?
Antworten: Wenn ein Webelement durchsucht werden soll, verwenden wir die Annotation @FindBy. Wir werden die alternativen Verwendungsmöglichkeiten von @FindBy zusammen mit den verschiedenen Locator-Strategien erläutern.
Wir haben bereits gesehen, wie man Version 1 von @FindBy verwendet:
@FindBy(id = 'cidkeyword') WebElement Symbol;
Version 2 von @FindBy übergibt den Eingabeparameter als Wie und Verwenden von .
Wie sucht nach der Locator-Strategie, mit der das Webelement identifiziert werden würde. Das Schlüsselwort mit definiert den Locator-Wert.
Siehe unten zum besseren Verständnis,
- How.ID durchsucht das Element mit Ich würde Strategie und das Element, das es zu identifizieren versucht, hat id = Schlüsselwort.
@FindBy(how = How.ID, using = ' cidkeyword') WebElement Symbol;
- How.CLASS_NAME durchsucht das Element mit Klassenname Strategie und das Element, das es zu identifizieren versucht, hat class = neue Klasse.
@FindBy(how = How.CLASS_NAME, using = 'newclass') WebElement Symbol;
F # 3) Gibt es einen Unterschied zwischen den beiden Versionen von @FindBy?
Antworten: Die Antwort lautet Nein, es gibt keinen Unterschied zwischen den beiden Versionen. Es ist nur so, dass die erste Version im Vergleich zur zweiten Version kürzer und einfacher ist.
F # 4) Was verwende ich in der Seitenfabrik, wenn eine Liste der zu lokalisierenden Webelemente vorhanden ist?
Antworten: Im üblichen Muster für das Design von Seitenobjekten haben wir driver.findElements (), um mehrere Elemente zu finden, die zu derselben Klasse oder demselben Tag-Namen gehören. Wie finden wir solche Elemente im Fall eines Seitenobjektmodells mit Pagefactory? Der einfachste Weg, solche Elemente zu erreichen, besteht darin, dieselbe Annotation @FindBy zu verwenden.
Ich verstehe, dass diese Linie für viele von Ihnen ein Kratzer zu sein scheint. Aber ja, es ist die Antwort auf die Frage.
Schauen wir uns das folgende Beispiel an:
Unter Verwendung des üblichen Seitenobjektmodells ohne Pagefactory verwenden Sie driver.findElements, um mehrere Elemente zu suchen, wie unten gezeigt:
private List multipleelements_driver_findelements = driver.findElements (By.class(“last”));
Dasselbe kann mit dem Seitenobjektmodell mit Pagefactory erreicht werden, wie unten angegeben:
@FindBy (how = How.CLASS_NAME, using = 'last') private List multipleelements_FindBy;
Grundsätzlich ist das Zuweisen der Elemente zu einer Liste vom Typ WebElement der Trick, unabhängig davon, ob Pagefactory beim Identifizieren und Lokalisieren der Elemente verwendet wurde oder nicht.
F # 5) Kann sowohl das Page-Objektdesign ohne Pagefactory als auch mit Pagefactory im selben Programm verwendet werden?
Antworten: Ja, sowohl das Seitenobjektdesign ohne Pagefactory als auch mit Pagefactory kann im selben Programm verwendet werden. Sie können das unten im Programm angegebene Programm durchgehen Antwort auf Frage 6 um zu sehen, wie beide im Programm verwendet werden.
Beachten Sie, dass das Pagefactory-Konzept mit der zwischengespeicherten Funktion bei dynamischen Elementen vermieden werden sollte, während das Design von Seitenobjekten für dynamische Elemente gut funktioniert. Pagefactory eignet sich jedoch nur für statische Elemente.
F # 6) Gibt es alternative Möglichkeiten, Elemente anhand mehrerer Kriterien zu identifizieren?
Wie rufe ich eine Methode mit einem Array von Objekten in Java auf?
Antworten: Die Alternative zum Identifizieren von Elementen anhand mehrerer Kriterien besteht in der Verwendung der Anmerkungen @FindAll und @FindBys. Diese Anmerkungen helfen dabei, einzelne oder mehrere Elemente zu identifizieren, abhängig von den Werten, die aus den darin übergebenen Kriterien abgerufen werden.
# 1) @FindAll:
@FindAll kann mehrere @FindBy enthalten und gibt alle Elemente zurück, die mit @FindBy in einer einzigen Liste übereinstimmen. @FindAll wird verwendet, um ein Feld in einem Seitenobjekt zu markieren, um anzugeben, dass für die Suche eine Reihe von @ FindBy-Tags verwendet werden soll. Anschließend wird nach allen Elementen gesucht, die einem der FindBy-Kriterien entsprechen.
Beachten Sie, dass die Elemente nicht garantiert in Dokumentreihenfolge vorliegen.
Die Syntax für die Verwendung von @FindAll lautet wie folgt:
@FindAll( { @FindBy(how = How.ID, using = 'foo'), @FindBy(className = 'bar') } )
Erläuterung: @FindAll sucht und identifiziert separate Elemente, die den einzelnen @ FindBy-Kriterien entsprechen, und listet sie auf. Im obigen Beispiel wird zuerst ein Element durchsucht, dessen ID = 'foo' ist, und dann das zweite Element mit className = 'bar' identifiziert.
Unter der Annahme, dass für jedes FindBy-Kriterium ein Element identifiziert wurde, führt @FindAll dazu, dass jeweils 2 Elemente aufgelistet werden. Denken Sie daran, dass für jedes Kriterium mehrere Elemente identifiziert werden können. Also, in einfachen Worten, @ Finde alle wirkt gleichwertig mit dem ODER Operator für die @ FindBy-Kriterien übergeben.
# 2) @FindBys:
FindBys wird verwendet, um ein Feld in einem Seitenobjekt zu markieren, um anzugeben, dass bei der Suche eine Reihe von @ FindBy-Tags in einer Kette verwendet werden soll, wie in ByChained beschrieben. Wenn die erforderlichen WebElement-Objekte allen angegebenen Kriterien entsprechen müssen, verwenden Sie die Annotation @FindBys.
Die Syntax für die Verwendung von @FindBys lautet wie folgt:
@FindBys( { @FindBy(name=”foo”) @FindBy(className = 'bar') } )
Erläuterung: @FindBys sucht und identifiziert Elemente, die allen @ FindBy-Kriterien entsprechen, und listet sie auf. Im obigen Beispiel werden Elemente gesucht, deren Name = 'foo' und Klassenname = 'bar'.
@FindAll führt dazu, dass 1 Element aufgelistet wird, wenn wir annehmen, dass in den angegebenen Kriterien ein Element mit dem Namen und dem Klassennamen identifiziert wurde.
Wenn nicht ein Element alle gefundenen FindBy-Bedingungen erfüllt, ist das Ergebnis von @FindBys null Elemente. Es könnte eine Liste von Webelementen identifiziert werden, wenn alle Bedingungen mehrere Elemente erfüllen. In einfachen Worten, @ FindBys wirkt gleichwertig mit dem UND Operator für die @ FindBy-Kriterien übergeben.
Lassen Sie uns die Implementierung aller oben genannten Anmerkungen anhand eines detaillierten Programms sehen:
Wir werden das im vorherigen Abschnitt angegebene Programm www.nseindia.com ändern, um die Implementierung der Anmerkungen @FindBy, @FindBys und @FindAll zu verstehen
# 1) Das Objekt-Repository von PagefactoryClass wird wie folgt aktualisiert:
List newlist = driver.findElements (By.tagName ('a'));
@ FindBy (wie = wie. VERLINKE DEN NAMEN mit = 'a')
Privat List findbyvalue;
@Finde alle ({ @ FindBy (className = 'sel'), @ FindBy (xpath = ”// a (@ id =’ tab5 ′) ”)})
Privat List findallvalue;
@ FindBys ({ @ FindBy (className = 'sel'), @ FindBy (xpath = ”// a (@ id =’ tab5 ′) ”)})
Privat List findbysvalue;
# 2) Eine neue Methode seeHowFindWorks () wird in die PagefactoryClass geschrieben und als letzte Methode in der Main-Klasse aufgerufen.
Die Methode ist wie folgt:
private void seeHowFindWorks() { System.out.println('driver.findElements(By.tagName()) '+newlist.size()); System.out.println('count of @FindBy- list elements '+findbyvalue.size()); System.out.println('count of @FindAll elements '+findallvalue.size()); for(int i=0;i Das folgende Ergebnis wird im Konsolenfenster nach der Ausführung des Programms angezeigt:

Versuchen wir nun, den Code im Detail zu verstehen:
# 1) Durch das Seitenobjekt-Entwurfsmuster identifiziert das Element 'Neue Liste' alle Tags mit dem Anker 'a'. Mit anderen Worten, wir erhalten eine Zählung aller Links auf der Seite.
Wir haben erfahren, dass die pagefactory @FindBy den gleichen Job wie die von driver.findElement () macht. Das Element findbyvalue wird erstellt, um die Anzahl aller Links auf der Seite über eine Suchstrategie mit einem Seitenfabrikkonzept zu ermitteln.
Es erweist sich als richtig, dass sowohl driver.findElement () als auch @FindBy denselben Job ausführen und dieselben Elemente identifizieren. Wenn Sie sich den Screenshot des resultierenden Konsolenfensters oben ansehen, sind die Anzahl der mit dem Element newlist identifizierten Links und die von findbyvalue gleich, d. H. 299 Links auf der Seite gefunden.
Das Ergebnis zeigte sich wie folgt:
driver.findElements(By.tagName()) 299 count of @FindBy- list elements 299
#zwei) Hier erläutern wir die Funktionsweise der Annotation @FindAll, die sich auf die Liste der Webelemente mit dem Namen findallvalue bezieht.
Wenn Sie sich die einzelnen @ FindBy-Kriterien in der Annotation @FindAll genau ansehen, suchen die ersten @ FindBy-Kriterien nach Elementen mit dem Klassennamen = 'sel' und die zweiten @ FindBy-Kriterien nach einem bestimmten Element mit XPath = “// a (@ id = 'tab5')
Lassen Sie uns nun F12 drücken, um die Elemente auf der Seite nseindia.com zu überprüfen und bestimmte Klarheit über Elemente zu erhalten, die den @ FindBy-Kriterien entsprechen.
Es gibt zwei Elemente auf der Seite, die dem Klassennamen = 'sel' entsprechen:
zu) Das Element 'Fundamentals' hat das Listen-Tag, d.h.
mit className = ”sel”. Siehe Schnappschuss unten

b) Ein weiteres Element 'Order Book' hat einen XPath mit einem Ankertag, dessen Klassenname 'sel' lautet.

c) Das zweite @FindBy mit XPath hat ein Ankertag, dessen Ich würde ist “ tab5 ”. Es gibt nur ein Element, das als Antwort auf die Suche identifiziert wurde: Fundamentals.
Siehe den Schnappschuss unten:

Als der nseindia.com-Test ausgeführt wurde, wurde die Anzahl der Elemente ermittelt, nach denen gesucht wurde.
@FindAll as 3. Die angezeigten Elemente für findallvalue waren: Fundamentals as the 0thIndexelement, Auftragsbuch als 1stIndexelement und Fundamentals wieder als 2ndIndexelement. Wir haben bereits erfahren, dass @FindAll Elemente für jedes @ FindBy-Kriterium separat identifiziert.
Gemäß demselben Protokoll wurden für die erste Kriteriumsuche, d. H. ClassName = 'sel', zwei Elemente identifiziert, die die Bedingung erfüllen, und es wurden 'Fundamentals' und 'Order Book' abgerufen.
Dann ging es zu den nächsten @ FindBy-Kriterien und konnte gemäß dem für das zweite @ FindBy angegebenen x-Pfad das Element 'Fundamentals' abrufen. Aus diesem Grund wurden schließlich jeweils 3 Elemente identifiziert.
Daher werden die Elemente nicht mit einer der @ FindBy-Bedingungen erfüllt, sondern es wird separat mit jedem der @ FindBy-Bedingungen behandelt und die Elemente werden ebenfalls identifiziert. Außerdem haben wir im aktuellen Beispiel festgestellt, dass nicht überprüft wird, ob die Elemente eindeutig sind ( Z.B. Das Element „Fundamentals“ in diesem Fall, das zweimal als Teil des Ergebnisses der beiden @ FindBy-Kriterien angezeigt wurde.
#3) Hier erläutern wir die Funktionsweise der Annotation @FindBys, die sich auf die Liste der Webelemente mit dem Namen findbysvalue bezieht. Auch hier suchen die ersten @ FindBy-Kriterien nach Elementen mit dem Klassennamen = 'sel' und die zweiten @ FindBy-Kriterien nach einem bestimmten Element mit xpath = '// a (@ id =' tab5 '.
Nach unserem Kenntnisstand sind die für die erste @ FindBy-Bedingung identifizierten Elemente 'Fundamentals' und 'Order Book' und das zweite @ FindBy-Kriterium 'Fundamentals'.
Wie wird sich das Ergebnis von @FindBys von dem von @FindAll unterscheiden? Wir haben im vorherigen Abschnitt erfahren, dass @FindBys dem bedingten Operator AND entspricht und daher nach einem Element oder einer Liste von Elementen sucht, die alle @ FindBy-Bedingungen erfüllen.
Gemäß unserem aktuellen Beispiel ist der Wert 'Fundamentals' das einzige Element, bei dem class = 'sel' und id = 'tab5' vorhanden sind, wodurch beide Bedingungen erfüllt werden. Aus diesem Grund ist die @ FindBys-Größe in unserem Testfall 1 und zeigt den Wert als 'Grundlagen' an.
Zwischenspeichern der Elemente in Pagefactory
Jedes Mal, wenn eine Seite geladen wird, werden alle Elemente auf der Seite erneut aufgerufen, indem ein Aufruf über @FindBy oder driver.findElement () aufgerufen wird, und es wird eine neue Suche nach den Elementen auf der Seite durchgeführt.
In den meisten Fällen, in denen die Elemente dynamisch sind oder sich zur Laufzeit ständig ändern, insbesondere wenn es sich um AJAX-Elemente handelt, ist es sicherlich sinnvoll, dass bei jedem Laden der Seite eine neue Suche nach allen Elementen auf der Seite durchgeführt wird.
Wenn die Webseite statische Elemente enthält, kann das Zwischenspeichern des Elements auf verschiedene Weise hilfreich sein. Wenn die Elemente zwischengespeichert werden, müssen sie beim Laden der Seite nicht erneut gefunden werden, sondern können auf das zwischengespeicherte Element-Repository verweisen. Dies spart viel Zeit und erhöht die Leistung.
Pagefactory bietet diese Funktion zum Zwischenspeichern der Elemente mithilfe einer Anmerkung @CacheLookUp .
Die Annotation weist den Treiber an, dieselbe Instanz des Locators aus dem DOM für die Elemente zu verwenden und sie nicht erneut zu durchsuchen, während die initElements-Methode der Seitenfabrik maßgeblich zum Speichern des zwischengespeicherten statischen Elements beiträgt. Die initElements erledigen den Caching-Job der Elemente.
Dies macht das PageFactory-Konzept gegenüber dem regulären Designmuster für Seitenobjekte besonders. Es hat seine eigenen Vor- und Nachteile, die wir etwas später besprechen werden. Beispielsweise ist die Anmeldeschaltfläche auf der Facebook-Startseite ein statisches Element, das zwischengespeichert werden kann und ein ideales Element ist, das zwischengespeichert werden kann.
Schauen wir uns nun an, wie die Annotation @CacheLookUp implementiert wird
Sie müssen zuerst ein Paket für Cachelookup wie folgt importieren:
import org.openqa.selenium.support.CacheLookup
Unten sehen Sie das Snippet, das die Definition eines Elements mit @CacheLookUp anzeigt. Sobald das UniqueElement zum ersten Mal durchsucht wird, speichert initElement () die zwischengespeicherte Version des Elements, sodass der Treiber beim nächsten Mal nicht nach dem Element sucht, sondern auf denselben Cache verweist und die Aktion für das Element rechts ausführt Weg.
@FindBy(id = 'unique') @CacheLookup private WebElement UniqueElement;
Lassen Sie uns nun anhand eines tatsächlichen Programms sehen, wie Aktionen auf dem zwischengespeicherten Webelement schneller sind als auf dem nicht zwischengespeicherten Webelement:
Das Programm nseindia.com weiter erweitern Ich habe eine weitere neue Methode monitorPerformance () geschrieben, in der ich ein zwischengespeichertes Element für das Suchfeld und ein nicht zwischengespeichertes Element für dasselbe Suchfeld erstelle.
Dann versuche ich, den Tag-Namen des Elements 3000 Mal sowohl für das zwischengespeicherte als auch für das nicht zwischengespeicherte Element abzurufen und die Zeit zu messen, die das zwischengespeicherte und das nicht zwischengespeicherte Element benötigt, um die Aufgabe abzuschließen.
Ich habe 3000 Mal darüber nachgedacht, damit wir einen sichtbaren Unterschied in den Timings für die beiden sehen können. Ich gehe davon aus, dass das zwischengespeicherte Element den Tag-Namen 3000-mal in kürzerer Zeit als das nicht zwischengespeicherte Element erhalten sollte.
Wir wissen jetzt, warum das zwischengespeicherte Element schneller arbeiten sollte, dh der Treiber wird angewiesen, das Element nach der ersten Suche nicht nachzuschlagen, sondern direkt weiter daran zu arbeiten. Dies ist bei dem nicht zwischengespeicherten Element, für das die Elementsuche durchgeführt wird, nicht der Fall alle 3000 mal und dann wird die Aktion darauf ausgeführt.
Unten ist der Code für die Methode monitorPerformance ():
private void monitorPerformance() { //non cached element long NoCache_StartTime = System.currentTimeMillis(); for(int i = 0; i <3000; i ++) { Searchbox.getTagName(); } long NoCache_EndTime = System.currentTimeMillis(); long NoCache_TotalTime=(NoCache_EndTime-NoCache_StartTime)/1000; System.out.println('Response time without caching Searchbox ' + NoCache_TotalTime+ ' seconds'); //cached element long Cached_StartTime = System.currentTimeMillis(); for(int i = 0; i < 3000; i ++) { cachedSearchbox.getTagName(); } long Cached_EndTime = System.currentTimeMillis(); long Cached_TotalTime=(Cached_EndTime - Cached_StartTime)/1000; System.out.println('Response time by caching Searchbox ' + Cached_TotalTime+ ' seconds'); }
Bei der Ausführung sehen wir das folgende Ergebnis im Konsolenfenster:
Gemäß dem Ergebnis wird die Aufgabe für das nicht zwischengespeicherte Element in abgeschlossen 82 Sekunden, während die Zeit, die zum Ausführen der Aufgabe für das zwischengespeicherte Element benötigt wurde, nur betrug 37 Sekunden. Dies ist in der Tat ein sichtbarer Unterschied in der Antwortzeit sowohl des zwischengespeicherten als auch des nicht zwischengespeicherten Elements.

F # 7) Was sind die Vor- und Nachteile der Annotation @CacheLookUp im Pagefactory-Konzept?
Antworten:
Vorteile @CacheLookUp und Situationen, die für seine Verwendung machbar sind:
@CacheLookUp ist möglich, wenn die Elemente statisch sind oder sich beim Laden der Seite überhaupt nicht ändern. Solche Elemente ändern die Laufzeit nicht. In solchen Fällen ist es ratsam, die Anmerkung zu verwenden, um die Gesamtgeschwindigkeit der Testausführung zu verbessern.
Nachteile der Annotation @CacheLookUp:
Der größte Nachteil beim Zwischenspeichern von Elementen mit der Annotation ist die Angst, häufig StaleElementReferenceExceptions zu erhalten.
Dynamische Elemente werden häufig mit solchen Elementen aktualisiert, die sich innerhalb weniger Sekunden oder Minuten des Zeitintervalls schnell ändern können.
Im Folgenden sind einige solcher Beispiele für dynamische Elemente aufgeführt:
- Auf der Webseite befindet sich eine Stoppuhr, die den Timer jede Sekunde aktualisiert.
- Ein Rahmen, der den Wetterbericht ständig aktualisiert.
- Eine Seite mit den Live-Updates von Sensex.
Diese sind für die Verwendung der Annotation @CacheLookUp überhaupt nicht ideal oder machbar. In diesem Fall besteht das Risiko, dass Sie die Ausnahme von StaleElementReferenceExceptions erhalten.
Beim Zwischenspeichern solcher Elemente wird während der Testausführung das DOM der Elemente geändert. Der Treiber sucht jedoch nach der Version des DOM, die bereits während des Zwischenspeicherns gespeichert wurde. Dadurch wird das veraltete Element vom Treiber nachgeschlagen, der auf der Webseite nicht mehr vorhanden ist. Aus diesem Grund wird die StaleElementReferenceException ausgelöst.
Fabrikklassen:
Pagefactory ist ein Konzept, das auf mehreren Factory-Klassen und -Schnittstellen basiert. In diesem Abschnitt erfahren Sie mehr über einige Factory-Klassen und -Schnittstellen. Nur wenige davon werden wir uns ansehen AjaxElementLocatorFactory , ElementLocatorFactory und DefaultElementFactory.
Haben wir uns jemals gefragt, ob Pagefactory eine Möglichkeit bietet, implizites oder explizites Warten auf das Element zu integrieren, bis eine bestimmte Bedingung erfüllt ist ( Beispiel: Bis ein Element sichtbar, aktiviert, anklickbar usw. ist)? Wenn ja, hier ist eine angemessene Antwort darauf.
AjaxElementLocatorFactory ist einer der maßgeblichen Mitwirkenden unter allen Fabrikklassen. Der Vorteil von AjaxElementLocatorFactory besteht darin, dass Sie der Objektseitenklasse einen Zeitüberschreitungswert für ein Webelement zuweisen können.
Obwohl Pagefactory keine explizite Wartefunktion bietet, gibt es eine Variante, um das Warten mithilfe der Klasse zu implizieren AjaxElementLocatorFactory . Diese Klasse kann integriert verwendet werden, wenn die Anwendung Ajax-Komponenten und -Elemente verwendet.
So implementieren Sie es im Code. Wenn wir im Konstruktor die Methode initElements () verwenden, können wir AjaxElementLocatorFactory verwenden, um eine implizite Wartezeit für die Elemente bereitzustellen.
PageFactory.initElements(driver, this); can be replaced with PageFactory.initElements( new AjaxElementLocatorFactory(driver, 20), this);
Die obige zweite Zeile des Codes impliziert, dass der Treiber eine Zeitüberschreitung von 20 Sekunden für alle Elemente auf der Seite festlegen muss, wenn jedes seiner Elemente geladen wird und wenn eines der Elemente nach einer Wartezeit von 20 Sekunden nicht gefunden wird, wird 'NoSuchElementException' ausgelöst für dieses fehlende Element.
Sie können das Warten auch wie folgt definieren:
public pageFactoryClass(WebDriver driver) { ElementLocatorFactory locateMe = new AjaxElementLocatorFactory(driver, 30); PageFactory.initElements(locateMe, this); this.driver = driver; }
Der obige Code funktioniert perfekt, da die Klasse AjaxElementLocatorFactory die Schnittstelle ElementLocatorFactory implementiert.
Hier verweist die übergeordnete Schnittstelle (ElementLocatorFactory) auf das Objekt der untergeordneten Klasse (AjaxElementLocatorFactory). Daher wird beim Zuweisen eines Timeouts mit AjaxElementLocatorFactory das Java-Konzept 'Upcasting' oder 'Laufzeitpolymorphismus' verwendet.
In Bezug auf die technische Funktionsweise erstellt die AjaxElementLocatorFactory zunächst einen AjaxElementLocator mit einer SlowLoadableComponent, die möglicherweise nicht vollständig geladen wurde, wenn load () zurückgegeben wird. Nach einem Aufruf von load () sollte die Methode isLoaded () weiterhin fehlschlagen, bis die Komponente vollständig geladen ist.
Mit anderen Worten, alle Elemente werden jedes Mal neu gesucht, wenn auf ein Element im Code zugegriffen wird, indem ein Aufruf von locator.findElement () aus der AjaxElementLocator-Klasse aufgerufen wird, der dann eine Zeitüberschreitung bis zum Laden über die SlowLoadableComponent-Klasse anwendet.
Nach dem Zuweisen eines Zeitlimits über AjaxElementLocatorFactory werden die Elemente mit der Annotation @CacheLookUp nicht mehr zwischengespeichert, da die Annotation ignoriert wird.
Es gibt auch eine Variation, wie Sie können Ruf den ... an initElements () Methode und wie Sie sollte nicht Ruf den ... an AjaxElementLocatorFactory Timeout für ein Element zuweisen.
# 1) Sie können anstelle des Treiberobjekts auch einen Elementnamen angeben, wie unten in der Methode initElements () gezeigt:
PageFactory.initElements( , this);
Die Methode initElements () in der obigen Variante ruft intern einen Aufruf der DefaultElementFactory-Klasse auf, und der Konstruktor von DefaultElementFactory akzeptiert das SearchContext-Schnittstellenobjekt als Eingabeparameter. Das Webtreiberobjekt und ein Webelement gehören beide zur SearchContext-Schnittstelle.
In diesem Fall wird die Methode initElements () im Voraus nur für das erwähnte Element initialisiert, und nicht alle Elemente auf der Webseite werden initialisiert.
#zwei) Hier ist jedoch eine interessante Wendung zu dieser Tatsache, die besagt, wie Sie das AjaxElementLocatorFactory-Objekt nicht auf eine bestimmte Weise aufrufen sollten. Wenn ich die obige Variante von initElements () zusammen mit AjaxElementLocatorFactory verwende, schlägt dies fehl.
Beispiel: Der folgende Code, d. H. Das Übergeben des Elementnamens anstelle des Treiberobjekts an die AjaxElementLocatorFactory-Definition, funktioniert nicht, da der Konstruktor für die AjaxElementLocatorFactory-Klasse nur das Webtreiberobjekt als Eingabeparameter verwendet und daher das SearchContext-Objekt mit dem Webelement nicht funktioniert.
PageFactory.initElements(new AjaxElementLocatorFactory(, 10), this);
F # 8) Ist die Verwendung der Seitenfabrik eine praktikable Option gegenüber dem regulären Seitenobjekt-Entwurfsmuster?
Antworten: Dies ist die wichtigste Frage, die die Leute haben, und deshalb habe ich mir überlegt, sie am Ende des Tutorials anzusprechen. Wir kennen das „In und Out“ von Pagefactory nun anhand seiner Konzepte, der verwendeten Anmerkungen, der von ihm unterstützten zusätzlichen Funktionen, der Implementierung über Code, der Vor- und Nachteile.
Wir bleiben jedoch bei dieser wesentlichen Frage: Wenn pagefactory so viele gute Dinge hat, warum sollten wir uns dann nicht an ihre Verwendung halten?
Pagefactory enthält das Konzept von CacheLookUp, das für dynamische Elemente wie die häufig aktualisierten Werte des Elements nicht realisierbar ist. Also, PageFactory ohne CacheLookUp, ist es eine gute Option? Ja, wenn die xpaths statisch sind.
Der Nachteil ist jedoch, dass die moderne Anwendung mit starken dynamischen Elementen gefüllt ist, bei denen wir wissen, dass das Seitenobjektdesign ohne Seitenfabrik letztendlich gut funktioniert. Funktioniert das Seitenfabrikkonzept jedoch genauso gut mit dynamischen xpaths? Vielleicht nicht. Hier ist ein kurzes Beispiel:
Auf der Webseite von nseindia.com sehen wir eine Tabelle wie unten angegeben.

Der xpath der Tabelle ist
'//*(@id='tab9Content')/table/tbody/tr(+count+)/td(1)'
Wir möchten Werte aus jeder Zeile für die erste Spalte 'Kaufmenge' abrufen. Dazu müssen wir den Zeilenzähler erhöhen, aber der Spaltenindex bleibt 1. Es gibt keine Möglichkeit, diesen dynamischen XPath in der Annotation @FindBy zu übergeben, da die Annotation statische Werte akzeptiert und keine Variable weitergegeben werden kann es.
Hier versagt die Seitenfabrik vollständig, während das übliche POM hervorragend damit funktioniert. Sie können eine for-Schleife verwenden, um den Zeilenindex mithilfe solcher dynamischer xpaths in der driver.findElement () -Methode zu erhöhen.
Fazit
Das Seitenobjektmodell ist ein Entwurfskonzept oder -muster, das im Selenium-Automatisierungsframework verwendet wird.
Die Benennung der Konvektion von Methoden ist im Seitenobjektmodell benutzerfreundlich. Der Code in POM ist leicht zu verstehen, wiederverwendbar und wartbar. Wenn sich in POM das Webelement ändert, reicht es aus, die Änderungen in der jeweiligen Klasse vorzunehmen, anstatt alle Klassen zu bearbeiten.
Pagefactory ist genau wie das übliche POM ein wunderbares Konzept. Wir müssen jedoch wissen, wo das übliche POM machbar ist und wo Pagefactory gut passt. In den statischen Anwendungen (in denen sowohl XPath als auch Elemente statisch sind) kann Pagefactory großzügig implementiert werden, mit zusätzlichen Vorteilen einer besseren Leistung.
Wenn die Anwendung sowohl dynamische als auch statische Elemente umfasst, können Sie alternativ eine gemischte Implementierung des POM mit Pagefactory und ohne Pagefactory gemäß der Machbarkeit für jedes Webelement durchführen.
Autor: Dieses Tutorial wurde von Shobha D. geschrieben. Sie arbeitet als Projektleiterin und verfügt über mehr als 9 Jahre Erfahrung in den Bereichen Handbuch, Automatisierung (Selen, IBM Rational Functional Tester, Java) und API-Tests (SOAPUI und Rest Assured in Java). .
Nun zu Ihnen für die weitere Implementierung von Pagefactory.
Viel Spaß beim Erkunden !!!
=> Besuchen Sie hier, um Selen von Grund auf neu zu lernen.
Literatur-Empfehlungen
- 30+ beste Selen-Tutorials: Lernen Sie Selen anhand realer Beispiele
- Effizientes Selenium-Scripting und Fehlerbehebungsszenarien - Selenium-Lernprogramm Nr. 27
- Debuggen von Selenium-Skripten mit Protokollen (Log4j Tutorial) - Selenium Tutorial # 26
- Einführung in JUnit Framework und seine Verwendung in Selenium Script - Selenium Tutorial # 11
- 7 Faktoren, die die Testschätzung des Selen-Automatisierungsprojekts beeinflussen - Selen-Tutorial Nr. 32
- Behauptungen in Selen unter Verwendung von Junit- und TestNG-Frameworks
- Verwendung des TestNG-Frameworks zum Erstellen von Selenium-Skripten - TestNG Selenium Tutorial # 12
- Erfahren Sie, wie Sie TestNG-Anmerkungen in Selen verwenden (mit Beispielen)