page object model with page factory selenium tutorial
Ten szczegółowy samouczek wyjaśnia wszystkie informacje o modelu obiektów strony (POM) z użyciem przykładów w programie Pagefactory. Możesz również nauczyć się implementacji POM w selenie:
W tym samouczku zrozumiemy, jak utworzyć model obiektu strony przy użyciu podejścia Page Factory. Skoncentrujemy się na:
- Klasa fabryczna
- Jak utworzyć podstawowy POM za pomocą wzorca Page Factory
- Różne adnotacje używane w podejściu do strony Factory
Zanim zobaczymy, czym jest Pagefactory i jak można go używać wraz z modelem obiektowym Page, zrozumiemy, czym jest Page Object Model, który jest powszechnie znany jako POM.
=> Odwiedź tutaj, aby zobaczyć serię treningów Selenium dla wszystkich.
Czego się nauczysz:
- Co to jest model obiektów strony (POM)?
- Co to jest Pagefactory?
- POM przy użyciu Page Factory
- Często Zadawane Pytania
- Wniosek
Co to jest model obiektów strony (POM)?
Terminologie teoretyczne opisują Model obiektu strony jako wzorzec projektowy używany do budowania repozytorium obiektów dla elementów WWW dostępnych w testowanej aplikacji. Niewielu innych nazywa to ramą automatyzacji Selenium dla danej testowanej aplikacji.
Jednak to, co zrozumiałem na temat terminu Page Object Model, to:
# 1) Jest to wzorzec projektowy, w którym masz oddzielny plik klasy Java odpowiadający każdemu ekranowi lub stronie w aplikacji. Plik klasy może zawierać repozytorium obiektów elementów UI, a także metod.
#dwa) W przypadku, gdy na stronie znajdują się ogromne elementy WWW, klasę repozytorium obiektów dla strony można oddzielić od klasy, która zawiera metody dla odpowiedniej strony.
Przykład: Jeśli strona Zarejestruj konto ma wiele pól wejściowych, może istnieć klasa RegisterAccountObjects.java, która tworzy repozytorium obiektów dla elementów interfejsu użytkownika na stronie rejestru kont.
Można utworzyć oddzielny plik klasy RegisterAccount.java rozszerzający lub dziedziczący RegisterAccountObjects, który zawiera wszystkie metody wykonujące różne akcje na stronie.
# 3) Poza tym może istnieć pakiet ogólny z plikiem {roperties, danymi testowymi programu Excel i typowymi metodami w pakiecie.
Przykład: DriverFactory, z którego można bardzo łatwo korzystać na wszystkich stronach aplikacji
Zrozumieć POM na przykładzie
Czek tutaj aby dowiedzieć się więcej o POM.
Poniżej znajduje się migawka strony internetowej:
Kliknięcie każdego z tych linków przekieruje użytkownika do nowej strony.
Oto migawka tego, jak struktura projektu z Selenium jest budowana przy użyciu modelu obiektowego Page odpowiadającego każdej stronie w witrynie. Każda klasa Java zawiera repozytorium obiektów i metody wykonywania różnych działań na stronie.
Poza tym będzie inny JUNIT lub TestNG lub plik klasy Java wywołujący wywołania plików klas tych stron.
Dlaczego używamy modelu obiektów strony?
Wokół korzystania z tego potężnego frameworka Selenium o nazwie POM lub model obiektowy strony budzi się zainteresowanie. Teraz pojawia się pytanie: „Dlaczego używać POM?”.
Prosta odpowiedź jest taka, że POM jest połączeniem opartych na danych, modułowych i hybrydowych struktur. Jest to podejście do systematycznego organizowania skryptów w taki sposób, aby zapewnić kontrolę jakości bez kłopotów z kodem, a także zapobiegać tworzeniu się nadmiarowego lub powielanego kodu.
Na przykład, jeśli nastąpi zmiana wartości lokalizatora na określonej stronie, bardzo łatwo jest zidentyfikować i dokonać tej szybkiej zmiany tylko w skrypcie odpowiedniej strony, bez wpływu na kod w innym miejscu.
Używamy koncepcji Page Object Model w Selenium Webdriver z następujących powodów:
- W tym modelu POM tworzone jest repozytorium obiektów. Jest niezależny od przypadków testowych i może być ponownie wykorzystany w innym projekcie.
- Konwencja nazewnictwa metod jest bardzo łatwa, zrozumiała i bardziej realistyczna.
- W modelu obiektowym Page tworzymy klasy stron, które mogą być ponownie użyte w innym projekcie.
- Model obiektowy Page jest łatwy w opracowywanym frameworku ze względu na kilka zalet.
- W tym modelu osobne klasy są tworzone dla różnych stron aplikacji internetowej, takich jak strona logowania, strona główna, strona szczegółów pracownika, strona zmiany hasła itp.
- Jeśli nastąpi jakakolwiek zmiana w jakimkolwiek elemencie strony internetowej, to musimy wprowadzić zmiany tylko w jednej klasie, a nie we wszystkich.
- Zaprojektowany skrypt jest bardziej użyteczny, czytelny i łatwiejszy w utrzymaniu w podejściu do modelu obiektów strony.
- Jego struktura projektowa jest dość prosta i zrozumiała.
- Może używać PageFactory w modelu obiektów strony w celu zainicjowania elementu sieci Web i przechowywania elementów w pamięci podręcznej.
- TestNG można również zintegrować z podejściem Page Object Model.
Wdrożenie prostego POM w selenie
# 1) Scenariusz automatyzacji
Teraz automatyzujemy dany scenariusz za pomocą Page Object Model.
Scenariusz wyjaśniono poniżej:
Krok 1: Uruchom witrynę „https: //demo.vtiger.com”.
Krok 2: Wprowadź prawidłowe poświadczenie.
Krok 3: Zaloguj się do serwisu.
Krok 4: Zweryfikuj stronę główną.
Krok 5: Wyloguj się z witryny.
Krok 6: Zamknij przeglądarkę.
# 2) Skrypty selenu dla powyższego scenariusza w POM
Teraz tworzymy Strukturę POM w Eclipse, jak wyjaśniono poniżej:
Krok 1: Utwórz projekt w Eclipse - struktura oparta na POM:
a) Utwórz projekt „Page Object Model”.
b) Utwórz 3 paczki w ramach projektu.
- biblioteka
- stron
- przypadki testowe
Biblioteka: W ramach tego umieszczamy te kody, które muszą być wywoływane wielokrotnie w naszych przypadkach testowych, takich jak uruchomienie przeglądarki, zrzuty ekranu itp. Użytkownik może dodać więcej klas w zależności od potrzeb projektu.
Strony: W ramach tego klasy są tworzone dla każdej strony w aplikacji internetowej i mogą dodawać więcej klas stron na podstawie liczby stron w aplikacji.
Przypadki testowe: W ramach tego piszemy przypadek testowy logowania i możemy dodać więcej przypadków testowych, zgodnie z wymaganiami, aby przetestować całą aplikację.
c) Zajęcia w ramach Pakietów pokazano na poniższym obrazku.
Krok dwa: Utwórz następujące klasy w pakiecie biblioteki.
Browser.java: W tej klasie zdefiniowano 3 przeglądarki (Firefox, Chrome i Internet Explorer) i jest ona wywoływana w przypadku testu logowania. W zależności od wymagań użytkownik może przetestować aplikację również w różnych przeglądarkach.
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: W tej klasie program do zrzutów ekranu jest napisany i jest wywoływany w przypadku testowym, gdy użytkownik chce zrobić zrzut ekranu, czy test zakończy się niepowodzeniem, czy też pomyślnie.
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(); } } }
Krok 3 : Utwórz klasy stron w pakiecie strony.
HomePage.java: Jest to klasa Strona główna, w której zdefiniowane są wszystkie elementy strony głównej i metody.
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: Jest to klasa strony logowania, w której zdefiniowane są wszystkie elementy strony logowania i metody.
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(); } }
Krok 4: Utwórz przypadki testowe dla scenariusza logowania.
LoginTestCase.java: To jest klasa LoginTestCase, w której wykonywany jest przypadek testowy. Użytkownik może również tworzyć więcej przypadków testowych zgodnie z potrzebami projektu.
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(); } }
Krok 5: Uruchom „LoginTestCase.java”.
Krok 6: Dane wyjściowe modelu obiektów strony:
- Uruchom przeglądarkę Chrome.
- Strona demonstracyjna zostanie otwarta w przeglądarce.
- Zaloguj się do serwisu demonstracyjnego.
- Zweryfikuj stronę główną.
- Wyloguj się z witryny.
- Zamknij przeglądarkę.
Przyjrzyjmy się teraz głównej koncepcji tego samouczka, która przykuwa uwagę, tj. „Pagefactory”.
Co to jest Pagefactory?
PageFactory to sposób na implementację „Page Object Model”. Tutaj kierujemy się zasadą oddzielenia repozytorium obiektów strony i metod testowych. Jest to wbudowana koncepcja modelu obiektów strony, która jest bardzo zoptymalizowana.
Przyjrzyjmy się teraz pojęciu Pagefactory.
# 1) Po pierwsze, koncepcja zwana Pagefactory, zapewnia alternatywny sposób pod względem składni i semantyki tworzenia repozytorium obiektów dla elementów WWW na stronie.
#dwa) Po drugie, używa nieco innej strategii inicjalizacji elementów sieci.
# 3) Repozytorium obiektów dla elementów sieciowych interfejsu użytkownika można zbudować za pomocą:
- Zwykle „POM bez Pagefactory” oraz
- Alternatywnie możesz użyć „POM with Pagefactory”.
Poniżej podano obrazowe przedstawienie tego samego:
Teraz przyjrzymy się wszystkim aspektom, które odróżniają zwykły POM od POM z Pagefactory.
a) Różnica w składni lokalizowania elementu przy użyciu zwykłego POM vs POM z Pagefactory.
Na przykład , Kliknij tutaj aby zlokalizować pole wyszukiwania, które pojawia się na stronie.
POM bez Pagefactory:
# 1) Poniżej opisano, jak zlokalizować pole wyszukiwania za pomocą zwykłego POM:
WebElement searchNSETxt=driver.findElement(By.id(“searchBox”));
# 2) Poniższy krok przekazuje wartość „inwestycja” do pola Szukaj w NSE.
searchNSETxt.sendkeys(“investment”);
POM przy użyciu Pagefactory:
# 1) Możesz zlokalizować pole wyszukiwania za pomocą Pagefactory, jak pokazano poniżej.
Adnotacja @FindBy jest używany w Pagefactory do identyfikacji elementu, podczas gdy POM bez Pagefactory używa rozszerzenia driver.findElement () metoda lokalizowania elementu.
Druga instrukcja dla Pagefactory po @FindBy przypisuje typ WebElement klasa, która działa dokładnie podobnie do przypisania nazwy elementu typu klasa WebElement jako zwracanego typu metody driver.findElement () który jest używany w zwykłym POM (w tym przykładzie searchNSETxt).
Przyjrzymy się @FindBy szczegółowe adnotacje w następnej części tego samouczka.
@FindBy(id = 'searchBox') WebElement searchNSETxt;
#dwa) Poniższy krok przekazuje wartość „inwestycja” do pola Search NSE, a składnia pozostaje taka sama, jak w przypadku zwykłego POM (POM bez Pagefactory).
searchNSETxt.sendkeys(“investment”);
b) Różnica w strategii inicjalizacji elementów sieci Web przy użyciu zwykłego POM vs POM z Pagefactory.
Korzystanie z POM bez Pagefactory:
Poniżej znajduje się fragment kodu do ustawiania ścieżki sterownika Chrome. Tworzona jest instancja WebDriver z nazwą sterownika, a ChromeDriver jest przypisywany do „sterownika”. Ten sam obiekt sterownika jest następnie używany do uruchomienia witryny National Stock Exchange, zlokalizowania pola wyszukiwania i wprowadzenia wartości ciągu w polu.
Punkt, który chciałbym tutaj podkreślić, to fakt, że gdy jest to POM bez fabryki strony, instancja sterownika jest tworzona początkowo i każdy element sieciowy jest świeżo inicjowany za każdym razem, gdy jest wywołanie tego elementu sieci Web przy użyciu driver.findElement () lub sterownika .findElements ().
Dlatego w nowym kroku driver.findElement () dla elementu struktura DOM jest ponownie skanowana i odświeżana identyfikacja elementu jest wykonywana na tej stronie.
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”);
Używanie POM z Pagefactory:
Oprócz używania adnotacji @FindBy zamiast metody driver.findElement (), poniższy fragment kodu jest dodatkowo używany dla Pagefactory. Statyczna metoda initElements () klasy PageFactory służy do inicjowania wszystkich elementów interfejsu użytkownika na stronie zaraz po załadowaniu strony.
public PagefactoryClass(WebDriver driver) { this.driver = driver; PageFactory.initElements(driver, this); }
Powyższa strategia sprawia, że podejście PageFactory różni się nieco od zwykłego POM. W zwykłym POM element sieciowy musi być jawnie zainicjowany, podczas gdy w podejściu Pagefactory wszystkie elementy są inicjowane za pomocą initElements () bez jawnej inicjalizacji każdego elementu sieci.
Na przykład: Jeśli element WebElement został zadeklarowany, ale nie został zainicjowany w zwykłym POM, zostanie zgłoszony błąd „inicjalizuj zmienną” lub wyjątek NullPointerException. Stąd w zwykłym POM każdy element WebElement musi być jawnie zainicjowany. PageFactory ma w tym przypadku przewagę nad zwykłym POM.
Nie inicjalizujmy elementu web BDate (POM bez Pagefactory), widać, że wyświetla się błąd „Inicjalizuj zmienną” i zachęca użytkownika do zainicjowania jej wartości null, dlatego nie można założyć, że elementy zostaną zainicjowane niejawnie po ich zlokalizowaniu.
Element BDate jawnie zainicjowany (POM bez Pagefactory):
Przyjrzyjmy się teraz kilku instancjom pełnego programu używającego PageFactory, aby wykluczyć wszelkie niejasności w zrozumieniu aspektu implementacji.
Przykład 1:
- Przejdź do „http://www.nseindia.com/”
- Z listy rozwijanej obok pola wyszukiwania wybierz „Walutowe instrumenty pochodne”.
- Wyszukaj „USDINR”. Sprawdź tekst „Dolar amerykański-rupia indyjska - USDINR” na wyświetlonej stronie.
Struktura programu:
- Tworzona jest stronafactoryClass.java, która zawiera repozytorium obiektów wykorzystujące koncepcję fabryki stron dla nseindia.com, czyli konstruktor do inicjowania wszystkich elementów sieci, metoda selectCurrentDerivative () w celu wybrania wartości z pola rozwijanego pola wyszukiwania, selectSymbol (), aby wybrać symbol na strona, która pojawia się next i verifytext (), aby sprawdzić, czy nagłówek strony jest zgodny z oczekiwaniami, czy nie.
- NSE_MainClass.java jest głównym plikiem klasy, który wywołuje wszystkie powyższe metody i wykonuje odpowiednie czynności w witrynie NSE.
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 Przykład 2:
- Wejdź na „https://www.shoppersstop.com/brands”
- Przejdź do linku Haute curry.
- Sprawdź, czy strona Haute Curry zawiera tekst „Zacznij coś nowego”.
Struktura programu
- shopperstopPagefactory.java, który zawiera repozytorium obiektów wykorzystujące koncepcję pagefactory dla shoppersstop.com, czyli konstruktor do inicjowania wszystkich elementów sieci, tworzone są metody closeExtraPopup () do obsługi wyskakującego okienka alertu, które się otwiera, clickOnHauteCurryLink (), aby kliknąć Haute Curry Połącz i zweryfikujStartNewSomething (), aby sprawdzić, czy strona Haute Curry zawiera tekst „Rozpocznij coś nowego”.
- Shopperstop_CallPagefactory.java to główny plik klasy, który wywołuje wszystkie powyższe metody i wykonuje odpowiednie czynności w witrynie NSE.
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 przy użyciu Page Factory
Samouczki wideo - POM With Page Factory
Część I.
część druga
Klasa Factory służy do uproszczenia i ułatwienia korzystania z obiektów strony.
- Najpierw musimy znaleźć elementy internetowe za pomocą adnotacji @FindBy w klasach stron .
- Następnie zainicjuj elementy za pomocą initElements () podczas tworzenia wystąpienia klasy strony.
# 1) @FindBy:
Adnotacja @FindBy jest używana w PageFactory do lokalizowania i deklarowania elementów sieci Web przy użyciu różnych lokalizatorów.Tutaj przekazujemy atrybut, jak również jego wartość używaną do lokalizowania elementu web do adnotacji @FindBy, a następnie deklarujemy WebElement.
Istnieją dwa sposoby wykorzystania adnotacji.
Na przykład:
@FindBy(how = How.ID, using='EmailAddress') WebElement Email; @FindBy(id='EmailAddress') WebElement Email;
Jednak ten pierwszy jest standardowym sposobem deklarowania WebElements.
'W jaki sposób' jest klasą i ma zmienne statyczne, takie jak ID, XPATH, CLASSNAME, LINKTEXT itp.
'za pomocą' - Aby przypisać wartość do zmiennej statycznej.
W powyższym przykład użyliśmy atrybutu „id” do zlokalizowania elementu internetowego „Email”. Podobnie możemy użyć następujących lokalizatorów z adnotacjami @FindBy:
- Nazwa klasy
- css
- Nazwa
- xpath
- Nazwa znacznika
- tekst linku
- częścioweLinkText
# 2) initElements ():
InitElements to statyczna metoda klasy PageFactory, która służy do inicjalizacji wszystkich elementów webowych znajdujących się w adnotacji @FindBy. W ten sposób łatwo tworzy się instancje klas Page.
initElements(WebDriver driver, java.lang.Class pageObjectClass)
Powinniśmy również zrozumieć, że POM przestrzega zasad OOPS.
- Elementy WebElement są deklarowane jako prywatne zmienne składowe (ukrywanie danych).
- Powiązanie WebElements z odpowiednimi metodami (hermetyzacja).
Kroki, aby utworzyć POM przy użyciu wzorca Page Factory
# 1) Utwórz osobny plik klasy Java dla każdej strony internetowej.
#dwa) W każdej klasie wszystkie elementy WebElements powinny być zadeklarowane jako zmienne (przy użyciu adnotacji - @FindBy) i zainicjowane za pomocą metody initElement (). Zadeklarowane elementy WebElements muszą zostać zainicjowane, aby mogły być użyte w metodach akcji.
# 3) Zdefiniuj odpowiednie metody działające na tych zmiennych.
Weźmy przykład prostego scenariusza:
- Otwórz adres URL aplikacji.
- Wpisz adres e-mail i hasło.
- Kliknij przycisk Zaloguj.
- Potwierdź pomyślny komunikat logowania na stronie wyszukiwania.
Warstwa strony
Tutaj mamy 2 strony,
- Strona główna - Strona, która otwiera się po wprowadzeniu adresu URL i na której podajemy dane do logowania.
- SearchPage - Strona wyświetlana po pomyślnym zalogowaniu.
W warstwie strony każda strona aplikacji internetowej jest deklarowana jako oddzielna klasa Java, a jej lokalizatory i akcje są tam wymienione.
Kroki tworzenia POM na przykładzie czasu rzeczywistego
# 1) Utwórz klasę Java dla każdej strony:
W tym przykład , uzyskamy dostęp do 2 stron internetowych: „Strona główna” i „Szukaj”.
Dlatego utworzymy 2 klasy Java w warstwie strony (lub w pakiecie, powiedzmy, com.automation.pages).
Package Name :com.automation.pages HomePage.java SearchPage.java
# 2) Zdefiniuj WebElements jako zmienne za pomocą Adnotacji @FindBy:
Będziemy wchodzić w interakcje z:
- E-mail, hasło, pole przycisku logowania na stronie głównej.
- Pomyślna wiadomość na stronie wyszukiwania.
Dlatego zdefiniujemy WebElements za pomocą @FindBy
Na przykład: Jeśli zamierzamy zidentyfikować EmailAddress za pomocą atrybutu id, to deklaracja jego zmiennej to
//Locator for EmailId field @FindBy(how=How.ID,using='EmailId') private WebElementEmailIdAddress;
# 3) Utwórz metody dla akcji wykonywanych na WebElements.
Poniższe czynności są wykonywane na WebElements:
- Wpisz akcję w polu Adres e-mail.
- Wpisz akcję w polu Hasło.
- Kliknij akcję na przycisku logowania.
Na przykład, Metody zdefiniowane przez użytkownika są tworzone dla każdej akcji w WebElement jako,
public void typeEmailId(String Id){ driver.findElement(EmailAddress).sendKeys(Id) }
Tutaj identyfikator jest przekazywany jako parametr w metodzie, ponieważ dane wejściowe zostaną przesłane przez użytkownika z głównego przypadku testowego.
Uwaga :W każdej klasie w warstwie strony należy utworzyć konstruktor, aby pobrać instancję sterownika z klasy głównej w warstwie testowej, a także zainicjować WebElements (Page Objects) zadeklarowane w klasie strony za pomocą PageFactory.InitElement () .
Nie inicjujemy tutaj sterownika, raczej jego instancja jest odbierana z klasy głównej podczas tworzenia obiektu klasy Page Layer.
InitElement () - służy do inicjalizacji zadeklarowanych elementów WebElements przy użyciu instancji sterownika z klasy głównej. Innymi słowy, elementy WebElements są tworzone przy użyciu instancji sterownika. Dopiero po zainicjowaniu elementów WebElements można ich używać w metodach do wykonywania akcji.
Dla każdej strony tworzone są dwie klasy Java, jak pokazano poniżej:
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. } }
Warstwa testowa
Przypadki testowe są zaimplementowane w tej klasie. Tworzymy osobny pakiet, powiedzmy com.automation.test, a następnie tworzymy tutaj klasę Java (MainClass.java)
Kroki tworzenia przypadków testowych:
- Zainicjuj sterownik i otwórz aplikację.
- Utwórz obiekt klasy PageLayer (dla każdej strony internetowej) i przekaż instancję sterownika jako parametr.
- Korzystając z utworzonego obiektu, wywołaj metody z klasy PageLayer (dla każdej strony) w celu wykonania akcji / weryfikacji.
- Powtarzaj krok 3, aż wszystkie czynności zostaną wykonane, a następnie zamknij sterownik.
//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(); } }
Hierarchia typów adnotacji używana do deklarowania elementów WebElements
Adnotacje pomagają w tworzeniu strategii lokalizacji elementów interfejsu użytkownika.
# 1) @FindBy
Jeśli chodzi o Pagefactory, @FindBy działa jak magiczna różdżka. Dodaje całej mocy koncepcji. Wiesz już, że adnotacja @FindBy w Pagefactory działa tak samo, jak w przypadku sterownika.findElement () w zwykłym modelu obiektów strony. Służy do lokalizowania WebElement / WebElements z jednym kryterium .
# 2) @FindBys
Służy do lokalizowania WebElement za pomocą więcej niż jedno kryterium i musi spełniać wszystkie podane kryteria. Kryteria te należy wspomnieć w relacji rodzic-dziecko. Innymi słowy, wykorzystuje to relację warunkową AND do zlokalizowania elementu WebElements przy użyciu określonych kryteriów. Używa wielu @FindBy do definiowania każdego kryterium.
Na przykład:
Kod źródłowy HTML WebElement:
W POM:
@FindBys({ @FindBy(id = 'searchId_1'), @FindBy(name = 'search_field') }) WebElementSearchButton;
W powyższym przykładzie element WebElement „SearchButton” znajduje się tylko wtedy, gdy tak jest pasuje do obu kryteria, których identyfikator to „searchId_1”, a nazwa to „search_field”. Zwróć uwagę, że pierwsze kryterium należy do tagu nadrzędnego, a drugie kryterium do tagu podrzędnego.
# 3) @FindAll
Służy do lokalizowania WebElement za pomocą więcej niż jedno kryterium i musi spełniać przynajmniej jedno z podanych kryteriów. Używa relacji warunkowych OR w celu zlokalizowania elementów WebElements. Używa wielu @FindBy do definiowania wszystkich kryteriów.
Na przykład:
Kod źródłowy HTML:
W POM:
@FindBys({ @FindBy(id = 'UsernameNameField_1'), // doesn’t match @FindBy(name = 'User_Id') //matches @FindBy(className = “UserName_r”) //matches }) WebElementUserName;
W powyższym przykładzie nazwa użytkownika WebElement jest umieszczona, jeśli tak pasuje do co najmniej jednego spośród wymienionych kryteriów.
# 4) @CacheLookUp
Kiedy WebElement jest częściej używany w przypadkach testowych, Selenium wyszukuje WebElement za każdym razem, gdy uruchamiany jest skrypt testowy. W takich przypadkach, w których określone elementy WebElement są używane globalnie dla wszystkich TC ( Na przykład, Scenariusz logowania ma miejsce dla każdego TC), ta adnotacja może służyć do utrzymywania tych elementów WebElement w pamięci podręcznej po ich pierwszym odczytaniu.
To z kolei pomaga w szybszym wykonywaniu kodu, ponieważ za każdym razem nie musi on wyszukiwać elementu WebElement na stronie, a raczej może uzyskać jego odniesienie z pamięci.
Może to być prefiks z dowolnym z @FindBy, @FindBys i @FindAll.
Na przykład:
@CacheLookUp @FindBys({ @FindBy(id = 'UsernameNameField_1'), @FindBy(name = 'User_Id') @FindBy(className = “UserName_r”) }) WebElementUserName;
Należy również pamiętać, że ta adnotacja powinna być używana tylko w przypadku elementów WebElements, których wartość atrybutu (np. Xpath, nazwa identyfikatora, nazwa klasy itp.) Nie zmienia się zbyt często. Gdy element WebElement zostanie zlokalizowany po raz pierwszy, zachowuje swoje odniesienie w pamięci podręcznej.
Tak więc następuje zmiana atrybutu WebElement po kilku dniach, Selenium nie będzie w stanie zlokalizować elementu, ponieważ ma już swoje stare odniesienie w swojej pamięci podręcznej i nie weźmie pod uwagę ostatniej zmiany w WebElement.
Więcej na temat PageFactory.initElements ()
Teraz, gdy już rozumiemy strategię Pagefactory dotyczącą inicjowania elementów sieci Web przy użyciu InitElements (), spróbujmy zrozumieć różne wersje tej metody.
Metoda, jaką znamy, przyjmuje obiekt sterownika i bieżący obiekt klasy jako parametry wejściowe i zwraca obiekt strony przez niejawną i proaktywną inicjalizację wszystkich elementów na stronie.
W praktyce użycie konstruktora, jak pokazano w powyższej sekcji, jest bardziej preferowane niż inne sposoby jego użycia.
Alternatywne sposoby wywoływania tej metody to:
# 1) Zamiast używać wskaźnika „this”, możesz utworzyć bieżący obiekt klasy, przekazać do niego instancję sterownika i wywołać metodę statyczną initElements z parametrami, tj. Obiekt sterownika i obiekt klasy, który właśnie został utworzony.
public PagefactoryClass(WebDriver driver) { //version 2 PagefactoryClass page=new PagefactoryClass(driver); PageFactory.initElements(driver, page); }
#dwa) Trzecim sposobem inicjowania elementów przy użyciu klasy Pagefactory jest użycie interfejsu API o nazwie „odbicie”. Tak, zamiast tworzyć obiekt klasy ze słowem kluczowym „new”, nazwa_klasy.class może zostać przekazana jako część parametru wejściowego initElements ().
public PagefactoryClass(WebDriver driver) { //version 3 PagefactoryClass page=PageFactory.initElements(driver, PagefactoryClass.class); }
Często Zadawane Pytania
P # 1) Jakie są różne strategie lokalizatora, które są używane w @FindBy?
Odpowiedź: Prostą odpowiedzią jest to, że nie ma różnych strategii lokalizatora, które są używane dla @FindBy.
Używają tych samych 8 strategii lokalizatora, których używa metoda findElement () w zwykłym POM:
- ID
- Nazwa
- Nazwa klasy
- xpath
- css
- Nazwa znacznika
- tekst linku
- częścioweLinkText
P # 2) Czy istnieją różne wersje stosowania adnotacji @FindBy?
Odpowiedź: Gdy istnieje element sieciowy do przeszukania, używamy adnotacji @FindBy. Opiszemy alternatywne sposoby korzystania z @FindBy wraz z różnymi strategiami lokalizatora.
Widzieliśmy już, jak korzystać z wersji 1 @FindBy:
@FindBy(id = 'cidkeyword') WebElement Symbol;
Wersja 2 @FindBy polega na przekazaniu parametru wejściowego jako W jaki sposób i Za pomocą .
W jaki sposób szuka strategii lokalizatora, za pomocą której zostanie zidentyfikowany element sieciowy. Słowo kluczowe za pomocą definiuje wartość lokalizatora.
Zobacz poniżej, aby lepiej zrozumieć,
- How.ID przeszukuje element za pomocą ID strategia, a element, który próbuje zidentyfikować, ma id = cidkeyword.
@FindBy(how = How.ID, using = ' cidkeyword') WebElement Symbol;
- How.CLASS_NAME przeszukuje element za pomocą Nazwa klasy strategia i element, który próbuje zidentyfikować, mają class = nowa klasa.
@FindBy(how = How.CLASS_NAME, using = 'newclass') WebElement Symbol;
P # 3) Czy istnieje różnica między dwiema wersjami @FindBy?
Odpowiedź: Odpowiedź brzmi: nie, nie ma różnicy między tymi dwiema wersjami. Tyle, że pierwsza wersja jest krótsza i łatwiejsza w porównaniu z drugą wersją.
P # 4) Czego używam w pagefactory w przypadku, gdy istnieje lista elementów sieci do zlokalizowania?
Odpowiedź: W zwykłym wzorcu projektowym obiektu strony mamy driver.findElements () do lokalizowania wielu elementów należących do tej samej klasy lub nazwy tagu, ale jak zlokalizować takie elementy w przypadku modelu obiektu strony z Pagefactory? Najłatwiejszym sposobem osiągnięcia takich elementów jest użycie tej samej adnotacji @FindBy.
Rozumiem, że ta kwestia wydaje się dla wielu z was drażniąca. Ale tak, to jest odpowiedź na pytanie.
Spójrzmy na poniższy przykład:
Używając zwykłego modelu obiektów strony bez Pagefactory, używasz driver.findElements do lokalizowania wielu elementów, jak pokazano poniżej:
private List multipleelements_driver_findelements = driver.findElements (By.class(“last”));
To samo można osiągnąć za pomocą modelu obiektów strony z Pagefactory, jak podano poniżej:
@FindBy (how = How.CLASS_NAME, using = 'last') private List multipleelements_FindBy;
Zasadniczo przypisanie elementów do listy typu WebElement załatwia sprawę niezależnie od tego, czy podczas identyfikacji i lokalizacji elementów użyto Pagefactory, czy nie.
P # 5) Czy projekt obiektu Page bez Pagefactory i z Pagefactory może być używany w tym samym programie?
Odpowiedź: Tak, zarówno projekt obiektu strony bez Pagefactory, jak iz Pagefactory może być używany w tym samym programie. Możesz przejść przez program podany poniżej w Odpowiedź na pytanie nr 6 aby zobaczyć, jak oba są używane w programie.
Należy pamiętać, że w przypadku elementów dynamicznych należy unikać koncepcji Pagefactory z funkcją buforowania, podczas gdy projektowanie obiektów strony sprawdza się dobrze w przypadku elementów dynamicznych. Jednak Pagefactory pasuje tylko do elementów statycznych.
P # 6) Czy istnieją alternatywne sposoby identyfikacji elementów w oparciu o wiele kryteriów?
jak wydrukować tablicę w odwrotnej kolejności java
Odpowiedź: Alternatywą do identyfikowania elementów na podstawie wielu kryteriów jest użycie adnotacji @FindAll i @FindBys. Te adnotacje pomagają zidentyfikować jeden lub wiele elementów w zależności od wartości pobranych z przesłanych w nim kryteriów.
# 1) @FindAll:
@FindAll może zawierać wiele @FindBy i zwróci wszystkie elementy, które pasują do dowolnego @FindBy na jednej liście. @FindAll służy do oznaczania pola w obiekcie strony, aby wskazać, że wyszukiwanie powinno używać serii tagów @FindBy. Następnie wyszuka wszystkie elementy, które pasują do któregokolwiek z kryteriów FindBy.
Zwróć uwagę, że nie ma gwarancji, że elementy są uporządkowane w dokumencie.
Składnia użycia @FindAll jest następująca:
@FindAll( { @FindBy(how = How.ID, using = 'foo'), @FindBy(className = 'bar') } )
Wyjaśnienie: @FindAll wyszuka i zidentyfikuje oddzielne elementy zgodne z każdym z kryteriów @FindBy i wyświetli je. W powyższym przykładzie najpierw wyszuka element, którego id = ”foo”, a następnie zidentyfikuje drugi element z className = ”bar”.
Zakładając, że dla każdego kryterium FindBy został zidentyfikowany jeden element, @FindAll spowoduje wyświetlenie odpowiednio 2 elementów. Pamiętaj, że dla każdego kryterium może istnieć wiele elementów. Zatem w prostych słowach @ Znajdź wszystko działa równoważne z LUB operator na przesłanych kryteriach @FindBy.
# 2) @FindBys:
FindBys służy do oznaczania pola w obiekcie strony, aby wskazać, że wyszukiwanie powinno używać serii tagów @FindBy w łańcuchu, zgodnie z opisem w ByChained. Gdy wymagane obiekty WebElement muszą spełniać wszystkie podane kryteria, użyj adnotacji @FindBys.
Składnia użycia @FindBys jest następująca:
@FindBys( { @FindBy(name=”foo”) @FindBy(className = 'bar') } )
Wyjaśnienie: @FindBys wyszuka i zidentyfikuje elementy spełniające wszystkie kryteria @FindBy i wyświetli je. W powyższym przykładzie wyszuka elementy, których nazwa = ”foo” i className = ”bar”.
@FindAll spowoduje wyświetlenie 1 elementu, jeśli założymy, że w podanych kryteriach był jeden element identyfikowany z nazwą i nazwą klasy.
Jeśli nie ma jednego elementu spełniającego wszystkie przekazane warunki FindBy, to wynik @FindBys będzie równy zero elementów. Lista elementów sieci mogłaby zostać zidentyfikowana, jeśli wszystkie warunki spełniają wiele elementów. Krótko mówiąc, @ FindBys działa równoważne z I operator na przesłanych kryteriach @FindBy.
Zobaczmy implementację całej powyższej adnotacji poprzez szczegółowy program:
Zmodyfikujemy program www.nseindia.com podany w poprzedniej sekcji, aby zrozumieć implementację adnotacji @FindBy, @FindBys i @FindAll
# 1) Repozytorium obiektów PagefactoryClass jest aktualizowane w następujący sposób:
Lista newlist = driver.findElements (By.tagName („a”));
@FindBy (jak = Jak. NAZWA ZNACZNIKA , używając = „a”)
prywatny Lista findbyvalue;
@Znajdź wszystko ({ @FindBy (className = „sel”), @FindBy (xpath = ”// a [@ id =’ tab5 ′] ”)})
prywatny Lista findallvalue;
@FindBys ({ @FindBy (className = „sel”), @FindBy (xpath = ”// a [@ id =’ tab5 ′] ”)})
prywatny Lista findbysvalue;
# 2) Nowa metoda seeHowFindWorks () została zapisana w PagefactoryClass i jest wywoływana jako ostatnia metoda w klasie Main.
Metoda jest następująca:
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 Poniżej podano wynik wyświetlany w oknie konsoli po wykonaniu programu:
Spróbujmy teraz szczegółowo zrozumieć kod:
# 1) Poprzez wzorzec projektowy obiektu strony element „newlist” identyfikuje wszystkie tagi z kotwicą „a”. Innymi słowy, otrzymujemy liczbę wszystkich linków na stronie.
Dowiedzieliśmy się, że pagefactory @FindBy wykonuje tę samą pracę, co driver.findElement (). Element findbyvalue jest tworzony w celu uzyskania liczby wszystkich linków na stronie za pomocą strategii wyszukiwania opartej na koncepcji Pagefactory.
Udowodniono, że zarówno driver.findElement (), jak i @FindBy wykonują tę samą pracę i identyfikują te same elementy. Jeśli spojrzysz na zrzut ekranu z wynikowego okna konsoli powyżej, liczba linków identyfikowanych za pomocą elementu newlist i findbyvalue są równe, tj. 299 linki znalezione na stronie.
Wynik pokazany poniżej:
driver.findElements(By.tagName()) 299 count of @FindBy- list elements 299
#dwa) Tutaj opiszemy działanie adnotacji @FindAll, która będzie odnosić się do listy elementów sieci o nazwie findallvalue.
Przyglądając się uważnie każdemu kryterium @FindBy w adnotacji @FindAll, pierwsze kryterium @FindBy wyszukuje elementy z className = 'sel', a drugie kryterium @FindBy wyszukuje określony element z XPath = “// a [@ id = „tab5”]
Naciśnijmy teraz F12, aby sprawdzić elementy na stronie nseindia.com i uzyskać pewne wyjaśnienia dotyczące elementów odpowiadających kryteriom @FindBy.
Na stronie znajdują się dwa elementy odpowiadające className = ”sel”:
do) Element „Fundamentals” ma tag listy, tj.
z className = ”sel”. Zobacz migawkę poniżej
b) Inny element „Księga zamówień” ma ścieżkę XPath z tagiem kotwicy, która ma nazwę klasy „sel”.
do) Drugi @FindBy z XPath ma tag kotwicy, którego ID jest ' tab5 ”. W odpowiedzi na wyszukiwanie zidentyfikowano tylko jeden element, czyli podstawy.
Zobacz migawkę poniżej:
Po wykonaniu testu nseindia.com otrzymaliśmy liczbę wyszukiwanych elementów.
@FindAll as 3. Wyświetlane elementy dla findallvalue to: Fundamentals as the 0thelement indeksu, Zamów książkę jako 1śwelement index i Fundamentals ponownie jako 2ndelement indeksu. Dowiedzieliśmy się już, że @FindAll identyfikuje elementy dla każdego kryterium @FindBy oddzielnie.
Zgodnie z tym samym protokołem, dla pierwszego wyszukiwania według kryterium, tj. ClassName = ”sel”, zidentyfikował dwa elementy spełniające warunek i pobrał „Fundamentals” i „Order Book”.
Następnie przeszedł do następnego kryterium @FindBy i zgodnie ze ścieżką x podaną dla drugiego @FindBy mógł pobrać element „Fundamentals”. Dlatego ostatecznie zidentyfikowano odpowiednio 3 elementy.
W związku z tym nie otrzymuje elementów spełniających którykolwiek z warunków @FindBy, ale zajmuje się oddzielnie każdym z warunków @FindBy i podobnie identyfikuje elementy. Dodatkowo w obecnym przykładzie widzieliśmy również, że nie obserwuje on, czy elementy są unikalne ( Na przykład. Element „Fundamentals” w tym przypadku wyświetlany dwukrotnie jako część wyniku dwóch kryteriów @FindBy)
# 3) W tym miejscu omówimy działanie adnotacji @FindBys, która będzie odnosić się do listy elementów sieci o nazwie findbysvalue. Również tutaj pierwsze kryterium @FindBy wyszukuje elementy z className = 'sel', a drugie kryterium @FindBy wyszukuje określony element z xpath = „// a [@ id =” tab5 ”).
Teraz, gdy wiemy, elementy zidentyfikowane dla pierwszego warunku @FindBy to „Fundamentals” i „Order Book”, a drugie kryterium @FindBy to „Fundamentals”.
Więc w jaki sposób wynik @FindBys będzie inny niż @FindAll? Dowiedzieliśmy się w poprzedniej sekcji, że @FindBys jest odpowiednikiem operatora warunkowego AND i dlatego szuka elementu lub listy elementów, które spełniają wszystkie warunki @FindBy.
Jak w naszym obecnym przykładzie, wartość „Fundamentals” jest jedynym elementem, który ma class = ”sel” i id = ”tab5”, tym samym spełniając oba warunki. Dlatego rozmiar @FindBys w naszej walizce testowej wynosi 1 i wyświetla wartość jako „Fundamentals”.
Buforowanie elementów w Pagefactory
Za każdym razem, gdy strona jest ładowana, wszystkie elementy na stronie są ponownie wyszukiwane przez wywołanie funkcji @FindBy lub driver.findElement () i następuje nowe wyszukiwanie elementów na stronie.
W większości przypadków, gdy elementy są dynamiczne lub zmieniają się w trakcie działania, zwłaszcza jeśli są to elementy AJAX, z pewnością ma sens, że przy każdym załadowaniu strony następuje nowe wyszukiwanie wszystkich elementów na stronie.
Jeśli strona internetowa zawiera elementy statyczne, buforowanie elementu może pomóc na wiele sposobów. Gdy elementy są buforowane, nie musi ponownie lokalizować elementów podczas ładowania strony, zamiast tego może odwoływać się do przechowywanego w pamięci repozytorium elementów. Oszczędza to dużo czasu i poprawia wydajność.
Pagefactory udostępnia tę funkcję buforowania elementów za pomocą adnotacji @CacheLookUp .
Adnotacja mówi sterownikowi, aby używał tej samej instancji lokalizatora z DOM dla elementów i nie przeszukiwał ich ponownie, podczas gdy metoda initElements z pagefactory wyraźnie przyczynia się do przechowywania buforowanego elementu statycznego. InitElements wykonują zadanie buforowania elementów.
To sprawia, że koncepcja Pagefactory jest wyjątkowa w stosunku do wzorca projektu zwykłego obiektu strony. Ma swoje zalety i wady, które omówimy nieco później. Na przykład przycisk logowania na stronie głównej Facebooka jest elementem statycznym, który można przechowywać w pamięci podręcznej i jest idealnym elementem do buforowania.
Przyjrzyjmy się teraz, jak zaimplementować adnotację @CacheLookUp
Najpierw musisz zaimportować pakiet dla Cachelookup, jak poniżej:
import org.openqa.selenium.support.CacheLookup
Poniżej znajduje się fragment wyświetlający definicję elementu za pomocą @CacheLookUp. Gdy tylko element UniqueElement jest przeszukiwany po raz pierwszy, initElement () przechowuje buforowaną wersję elementu, dzięki czemu następnym razem sterownik nie szuka elementu, zamiast tego odwołuje się do tej samej pamięci podręcznej i wykonuje akcję na elemencie po prawej stronie z dala.
@FindBy(id = 'unique') @CacheLookup private WebElement UniqueElement;
Przyjrzyjmy się teraz przez rzeczywisty program, w jaki sposób działania na zbuforowanym elemencie web są szybsze niż na niebuforowanym elemencie web:
Dalsze ulepszanie programu nseindia.com Napisałem kolejną nową metodę monitorPerformance (), w której tworzę buforowany element dla pola wyszukiwania i niebuforowany element dla tego samego pola wyszukiwania.
Następnie próbuję uzyskać nazwę zmiennej elementu 3000 razy zarówno dla elementu buforowanego, jak i niebuforowanego i próbuję zmierzyć czas potrzebny na wykonanie zadania zarówno przez element buforowany, jak i niebuforowany.
Rozważyłem 3000 razy, dzięki czemu możemy zobaczyć widoczną różnicę w czasie dla tych dwóch. Spodziewam się, że element buforowany powinien zakończyć pobieranie zmiennej 3000 razy w krótszym czasie w porównaniu z elementem niebuforowanym.
Teraz wiemy, dlaczego buforowany element powinien działać szybciej, tj. Sterownik jest instruowany, aby nie szukał elementu po pierwszym wyszukiwaniu, ale bezpośrednio kontynuował pracę nad nim, a nie jest tak w przypadku elementu niebuforowanego, w którym wyszukiwanie elementu jest wykonywane dla wszystkie 3000 razy, a następnie wykonywana jest na nim akcja.
Poniżej znajduje się kod metody 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'); }
Podczas wykonywania w oknie konsoli zobaczymy poniższy wynik:
Zgodnie z wynikiem zadanie dotyczące elementu niebuforowanego jest zakończone w 82 sekund, podczas gdy czas potrzebny na ukończenie zadania na elemencie w pamięci podręcznej był tylko 37 sekundy. Jest to rzeczywiście widoczna różnica w czasie odpowiedzi zarówno elementu buforowanego, jak i niebuforowanego.
P # 7) Jakie są zalety i wady adnotacji @CacheLookUp w koncepcji Pagefactory?
Odpowiedź:
Zalety @CacheLookUp i sytuacje możliwe do użycia:
@CacheLookUp jest wykonalne, gdy elementy są statyczne lub nie zmieniają się wcale podczas ładowania strony. Takie elementy nie zmieniają czasu działania. W takich przypadkach wskazane jest użycie adnotacji w celu zwiększenia ogólnej szybkości wykonywania testu.
Wady adnotacji @CacheLookUp:
Największą wadą buforowania elementów z adnotacją jest strach przed częstym uzyskiwaniem StaleElementReferenceExceptions.
Elementy dynamiczne odświeżane są dość często tymi, które są podatne na szybką zmianę w ciągu kilku sekund lub minut odstępu czasu.
Poniżej znajduje się kilka takich przykładów elementów dynamicznych:
- Posiadanie stopera na stronie internetowej, który aktualizuje licznik co sekundę.
- Ramka, która stale aktualizuje prognozę pogody.
- Strona przedstawiająca aktualne aktualizacje Sensex.
W ogóle nie są one idealne ani wykonalne do użycia adnotacji @CacheLookUp. W przeciwnym razie istnieje ryzyko uzyskania wyjątku StaleElementReferenceExceptions.
Podczas buforowania takich elementów, podczas wykonywania testów, DOM elementów jest zmieniany, jednak sterownik szuka wersji DOM, która była już przechowywana podczas buforowania. To powoduje, że nieaktualny element jest wyszukiwany przez sterownik, którego już nie ma na stronie internetowej. Dlatego jest zgłaszany StaleElementReferenceException.
Klasy fabryczne:
Pagefactory to koncepcja oparta na wielu klasach i interfejsach fabryki. Dowiemy się tutaj o kilku klasach fabrycznych i interfejsach w tej sekcji. Niewiele z nich przyjrzymy się AjaxElementLocatorFactory , ElementLocatorFactory i DefaultElementFactory.
Czy kiedykolwiek zastanawialiśmy się, czy Pagefactory zapewnia jakikolwiek sposób włączenia Niejawnego lub jawnego czekania na element, aż określony warunek zostanie spełniony ( Przykład: Dopóki element nie będzie widoczny, włączony, klikalny itp.)? Jeśli tak, oto właściwa odpowiedź.
AjaxElementLocatorFactory jest jednym z najważniejszych współtwórców wszystkich klas fabryk. Zaletą AjaxElementLocatorFactory jest to, że można przypisać wartość limitu czasu dla elementu WWW do klasy strony Object.
Chociaż Pagefactory nie zapewnia jawnej funkcji oczekiwania, istnieje jednak wariant niejawnego oczekiwania przy użyciu tej klasy AjaxElementLocatorFactory . Ta klasa może być używana, gdy aplikacja używa komponentów i elementów Ajax.
Oto jak zaimplementujesz to w kodzie. W konstruktorze, gdy używamy metody initElements (), możemy użyć AjaxElementLocatorFactory, aby zapewnić niejawne oczekiwanie na elementy.
PageFactory.initElements(driver, this); can be replaced with PageFactory.initElements( new AjaxElementLocatorFactory(driver, 20), this);
Z powyższego drugiego wiersza kodu wynika, że sterownik ustawia limit czasu równy 20 sekund dla wszystkich elementów strony, gdy każdy z jego ładuje się, a jeśli którykolwiek element nie zostanie znaleziony po odczekaniu 20 sekund, zostanie wyrzucony wyjątek „NoSuchElementException” dla tego brakującego elementu.
Możesz również zdefiniować czas oczekiwania jak poniżej:
public pageFactoryClass(WebDriver driver) { ElementLocatorFactory locateMe = new AjaxElementLocatorFactory(driver, 30); PageFactory.initElements(locateMe, this); this.driver = driver; }
Powyższy kod działa doskonale, ponieważ klasa AjaxElementLocatorFactory implementuje interfejs ElementLocatorFactory.
Tutaj interfejs nadrzędny (ElementLocatorFactory) odwołuje się do obiektu klasy potomnej (AjaxElementLocatorFactory). W związku z tym podczas przypisywania limitu czasu za pomocą AjaxElementLocatorFactory używana jest koncepcja Java „upcasting” lub „runtime polimorfizmu”.
W odniesieniu do tego, jak to działa technicznie, AjaxElementLocatorFactory najpierw tworzy AjaxElementLocator przy użyciu SlowLoadableComponent, który mógł nie zakończyć ładowania, gdy funkcja load () powróci. Po wywołaniu metody load () metoda isLoaded () powinna nadal kończyć się niepowodzeniem do momentu pełnego załadowania składnika.
Innymi słowy, wszystkie elementy będą na nowo wyszukiwane za każdym razem, gdy dostęp do elementu w kodzie zostanie uzyskany przez wywołanie funkcji locator.findElement () z klasy AjaxElementLocator, która następnie stosuje limit czasu do załadowania przez klasę SlowLoadableComponent.
Ponadto po przypisaniu limitu czasu za pośrednictwem AjaxElementLocatorFactory elementy z adnotacją @CacheLookUp nie będą już buforowane, ponieważ adnotacja zostanie zignorowana.
Istnieje również różnica w tym, jak możesz Zadzwoń do initElements () metoda i jak ty nie powinieneś Zadzwoń do AjaxElementLocatorFactory aby przypisać limit czasu elementowi.
# 1) Możesz także określić nazwę elementu zamiast obiektu sterownika, jak pokazano poniżej w metodzie initElements ():
PageFactory.initElements( , this);
initElements () w powyższym wariancie wewnętrznie wywołuje wywołanie klasy DefaultElementFactory, a konstruktor DefaultElementFactory akceptuje obiekt interfejsu SearchContext jako parametr wejściowy. Obiekt sterownika sieci Web i element sieci Web należą do interfejsu SearchContext.
W takim przypadku metoda initElements () zainicjuje z góry tylko wspomniany element i nie wszystkie elementy na stronie zostaną zainicjowane.
#dwa) Jednak tutaj jest interesujący zwrot w tym fakcie, który określa, jak nie należy wywoływać obiektu AjaxElementLocatorFactory w określony sposób. Jeśli użyję powyższego wariantu initElements () wraz z AjaxElementLocatorFactory, to się nie powiedzie.
Przykład: Poniższy kod, tj. Przekazanie nazwy elementu zamiast obiektu sterownika do definicji AjaxElementLocatorFactory, nie zadziała jako konstruktor dla klasy AjaxElementLocatorFactory, jako parametr wejściowy przyjmuje tylko obiekt sterownika WWW, a zatem obiekt SearchContext z elementem WWW nie będzie dla niego działał.
PageFactory.initElements(new AjaxElementLocatorFactory(, 10), this);
P # 8) Czy użycie pagefactory jest wykonalną opcją zamiast standardowego wzorca projektu obiektu strony?
Odpowiedź: To jest najważniejsze pytanie, jakie mają ludzie, dlatego pomyślałem o tym na końcu samouczka. Teraz znamy wszystkie elementy Pagefactory, zaczynając od koncepcji, używanych adnotacji, dodatkowych funkcji, które obsługuje, implementacji za pomocą kodu oraz zalet i wad.
Pozostajemy jednak z tym zasadniczym pytaniem, że jeśli Pagefactory ma tak wiele dobrych rzeczy, dlaczego nie mielibyśmy trzymać się jej stosowania.
Pagefactory zawiera koncepcję CacheLookUp, która, jak widzieliśmy, jest niewykonalna w przypadku elementów dynamicznych, takich jak wartości elementu, który jest często aktualizowany. Tak więc, pagefactory bez CacheLookUp, czy jest to dobra opcja? Tak, jeśli ścieżki xpath są statyczne.
Jednak wadą jest to, że współczesna aplikacja jest wypełniona ciężkimi dynamicznymi elementami, o których wiemy, że projekt obiektu strony bez pagefactory działa ostatecznie dobrze, ale czy koncepcja pagefactory działa równie dobrze z dynamicznymi ścieżkami xpath? Może nie. Oto krótki przykład:
Na stronie internetowej nseindia.com widzimy tabelę podaną poniżej.
Ścieżka x tabeli to
'//*[@id='tab9Content']/table/tbody/tr[+count+]/td[1]'
Chcemy pobrać wartości z każdego wiersza dla pierwszej kolumny „Kup ilość”. Aby to zrobić, będziemy musieli zwiększyć licznik wierszy, ale indeks kolumny pozostanie 1. Nie ma sposobu, abyśmy mogli przekazać tę dynamiczną ścieżkę XPath w adnotacji @FindBy, ponieważ adnotacja akceptuje wartości, które są statyczne i nie można przekazać żadnej zmiennej to.
W tym miejscu fabryka stroniców całkowicie zawodzi, podczas gdy zwykły POM działa z nią świetnie. Możesz łatwo użyć pętli for do zwiększenia indeksu wierszy, używając takich dynamicznych ścieżek xpath w metodzie driver.findElement ().
Wniosek
Page Object Model to koncepcja projektowa lub wzorzec używany w ramach automatyzacji Selenium.
Konwekcja nazewnictwa metod jest przyjazna dla użytkownika w modelu obiektów strony. Kod w POM jest łatwy do zrozumienia, wielokrotnego użytku i konserwacji. W POM, jeśli nastąpi jakakolwiek zmiana w elemencie web, to wystarczy wprowadzić zmiany w odpowiedniej klasie, zamiast edytować wszystkie klasy.
Pagefactory, podobnie jak zwykły POM, jest wspaniałą koncepcją do zastosowania. Musimy jednak wiedzieć, gdzie można zastosować zwykły POM i gdzie dobrze pasuje Pagefactory. W aplikacjach statycznych (gdzie zarówno XPath, jak i elementy są statyczne), Pagefactory można swobodnie zaimplementować z dodatkowymi korzyściami w postaci lepszej wydajności.
Alternatywnie, gdy aplikacja zawiera zarówno elementy dynamiczne, jak i statyczne, możesz mieć mieszaną implementację pom z Pagefactory i bez Pagefactory, zgodnie z wykonalnością dla każdego elementu internetowego.
Autor: Ten samouczek został napisany przez Shobha D. Pracuje jako kierownik projektu i ma ponad 9-letnie doświadczenie w ręcznej, automatyzacji (Selenium, IBM Rational Functional Tester, Java) i testowaniu API (SOAPUI i Rest assured in Java) .
Teraz czas na dalsze wdrażanie Pagefactory.
Miłego odkrywania !!!
=> Odwiedź tutaj, aby nauczyć się selenu od podstaw.
rekomendowane lektury
- 30+ najlepszych samouczków dotyczących selenu: naucz się selenu z prawdziwymi przykładami
- Efektywne skrypty Selenium i scenariusze rozwiązywania problemów - samouczek Selenium nr 27
- Debugowanie skryptów Selenium za pomocą dzienników (samouczek Log4j) - samouczek Selenium # 26
- Wprowadzenie do JUnit Framework i jego wykorzystanie w skrypcie Selenium - Samouczek Selenium # 11
- 7 Czynników wpływających na estymację testową projektu Selenium Automation - Samouczek Selenium # 32
- Assertions in Selenium using Junit and TestNG Frameworks
- Jak używać platformy TestNG do tworzenia skryptów selenium - Samouczek TestNG Selenium nr 12
- Dowiedz się, jak używać adnotacji TestNG w selenie (z przykładami)