Model obiektu strony i fabryka w Selenium
Co to jest model obiektowy strony?
Model obiektowy strony (POM) to wzorzec projektowy, powszechnie stosowany w automatyzacji testów, który tworzy Repozytorium Obiektów dla elementów interfejsu WWW. Zaletą modelu jest to, że ogranicza duplikację kodu i poprawia utrzymanie testów.
W tym modelu dla każdej strony internetowej w aplikacji powinna istnieć odpowiadająca jej klasa Page. Ta klasa Page będzie identyfikować WebElements tej strony internetowej i zawiera również metody Page, które wykonują operacje na tych WebElements. Nazwy tych metod powinny być podane zgodnie z zadaniem, które wykonują, tj. jeśli program ładujący czeka na pojawienie się bramki płatności, nazwa metody POM może być waitForPaymentScreenDisplay().
Dlaczego model obiektowy strony?
Rozpoczęcie automatyzacji interfejsu użytkownika w Selenium WebDriver NIE jest trudnym zadaniem. Wystarczy znaleźć elementy i wykonać na nich operacje.
Rozważmy prosty skrypt umożliwiający zalogowanie się do witryny internetowej
Jak widać, jedyne, co robimy, to znajdowanie elementów i wypełnianie dla nich wartości.
To jest mały skrypt. Konserwacja skryptu wygląda na łatwą. Ale z czasem zestaw testów będzie się powiększał. W miarę dodawania coraz większej liczby linii do kodu sytuacja staje się trudniejsza.
Główny problem związany z konserwacją skryptów polega na tym, że jeśli 10 różnych skryptów używa tego samego elementu strony, każda zmiana w tym elemencie wymaga zmiany wszystkich 10 skryptów. Jest to czasochłonne i podatne na błędy.
Lepszym podejściem do obsługi skryptów jest utworzenie osobnego pliku klasy, który będzie wyszukiwał elementy sieciowe, wypełniał je lub weryfikował. Tej klasy można ponownie użyć we wszystkich skryptach korzystających z tego elementu. W przyszłości, jeśli nastąpi zmiana w elemencie WWW, będziemy musieli dokonać zmiany tylko w 1 pliku klasy, a nie w 10 różnych skryptach.
To podejście nazywa się modelem obiektowym strony SeleniumPomaga uczynić kod bardziej czytelnym, łatwiejszym w utrzymaniu i nadającym się do ponownego wykorzystania.
Zalety POM
- Wzorzec projektowy obiektu strony mówi, że operacje i przepływy w interfejsie użytkownika powinny być oddzielone od weryfikacji. Ta koncepcja sprawia, że nasz kod jest czystszy i łatwiejszy do zrozumienia.
- Drugą korzyścią jest to, że repozytorium obiektów jest niezależne od przypadków testowych, dzięki czemu możemy używać tego samego repozytorium obiektów do różnych celów za pomocą różnych narzędzi. Na przykład możemy zintegrować model obiektowy strony z Selenium w TestNG/JUnit za funkcjonalne Testowanie i jednocześnie z JBehave/Cucumber do testów akceptacyjnych.
- Kod staje się mniejszy i zoptymalizowany ze względu na metody stron wielokrotnego użytku w klasach POM.
- Metody otrzymują bardziej realistyczne nazwy, które można łatwo odwzorować na operacje wykonywane w interfejsie użytkownika. Np. jeśli po kliknięciu przycisku zostaniemy przeniesieni na stronę główną, nazwa metody będzie wyglądać następująco: 'gotoHomePage()'.
Jak wdrożyć POM?
Prosty POM:
Jest to podstawowa struktura modelu obiektowego strony, w której wszystkie elementy sieciowe AUT a metody operujące na tych elementach sieci Web są przechowywane w pliku klasy. Takie zadanie, jak weryfikacja, powinno być oddzielne jako część metod testowych.
Kompletny przykład
Przypadek testowy: Przejdź do witryny demonstracyjnej Guru99.
Krok 1) Przejdź do witryny demonstracyjnej Guru99
Krok 2) Sprawdź, czy na stronie głównej znajduje się tekst „Guru99 Bank”.
Krok 3) Zaloguj się do aplikacji
Krok 4) Sprawdź, czy strona główna zawiera tekst „Identyfikator menedżera: demo”
Tutaj mamy do czynienia z 2 stronami
- Strona logowania
- Strona główna (wyświetlana po zalogowaniu)
W związku z tym tworzymy 2 POM w Selenium Klasy
Guru99 Strona logowania POM
package pages; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; public class Guru99Login { WebDriver driver; By user99GuruName = By.name("uid"); By password99Guru = By.name("password"); By titleText =By.className("barone"); By login = By.name("btnLogin"); public Guru99Login(WebDriver driver){ this.driver = driver; } //Set user name in textbox public void setUserName(String strUserName){ driver.findElement(user99GuruName).sendKeys(strUserName); } //Set password in password textbox public void setPassword(String strPassword){ driver.findElement(password99Guru).sendKeys(strPassword); } //Click on login button public void clickLogin(){ driver.findElement(login).click(); } //Get the title of Login Page public String getLoginTitle(){ return driver.findElement(titleText).getText(); } /** * This POM method will be exposed in test case to login in the application * @param strUserName * @param strPasword * @return */ public void loginToGuru99(String strUserName,String strPasword){ //Fill user name this.setUserName(strUserName); //Fill password this.setPassword(strPasword); //Click Login button this.clickLogin(); } }
Strona główna Guru99 POM w Selenium
package pages; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; public class Guru99HomePage { WebDriver driver; By homePageUserName = By.xpath("//table//tr[@class='heading3']"); public Guru99HomePage(WebDriver driver){ this.driver = driver; } //Get the User name from Home Page public String getHomePageDashboardUserName(){ return driver.findElement(homePageUserName).getText(); } }
Guru99 Prosty POM w Selenium Przypadek testowy
package test; import java.util.concurrent.TimeUnit; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; import org.testng.Assert; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; import pages.Guru99HomePage; import pages.Guru99Login; public class Test99GuruLogin { String driverPath = "C:\\geckodriver.exe"; WebDriver driver; Guru99Login objLogin; Guru99HomePage objHomePage; @BeforeTest public void setup(){ System.setProperty("webdriver.gecko.driver", driverPath); driver = new FirefoxDriver(); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); driver.get("https://demo.guru99.com/V4/"); } /** * This test case will login in https://demo.guru99.com/V4/ * Verify login page title as guru99 bank * Login to application * Verify the home page using Dashboard message */ @Test(priority=0) public void test_Home_Page_Appear_Correct(){ //Create Login Page object objLogin = new Guru99Login(driver); //Verify login page title String loginPageTitle = objLogin.getLoginTitle(); Assert.assertTrue(loginPageTitle.toLowerCase().contains("guru99 bank")); //login to application objLogin.loginToGuru99("mgr123", "mgr!23"); // go the next page objHomePage = new Guru99HomePage(driver); //Verify home page Assert.assertTrue(objHomePage.getHomePageDashboardUserName().toLowerCase().contains("manger id : mgr123")); }
W czym jest Page Factory Selenium?
Strona Fabryki w Selenium jest wbudowaną koncepcją frameworka Page Object Model dla Selenium WebDriver, ale jest bardzo zoptymalizowany. Służy do inicjowania obiektów Page lub do tworzenia instancji samego obiektu Page. Służy również do inicjowania elementów klasy Page bez użycia „FindElement/s”.
Tutaj również kierujemy się koncepcją rozdzielenia Repozytorium Obiektów Strony i Metod Testowania. Dodatkowo przy pomocy klasy PageFactory w Selenium, używamy adnotacji @FindBy aby znaleźć element WebElement. Do inicjowania elementów sieciowych używamy metody initElements
@FindBy Mogę zaakceptować tagName, częściowyLinkText, nazwa, linkText, identyfikator, css, nazwa klasy, xpath jako atrybuty.
Spójrzmy na ten sam przykład co powyżej, używając Page Factory
Strona logowania Guru99 w Page Factory
package PageFactory; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class Guru99Login { /** * All WebElements are identified by @FindBy annotation */ WebDriver driver; @FindBy(name="uid") WebElement user99GuruName; @FindBy(name="password") WebElement password99Guru; @FindBy(className="barone") WebElement titleText; @FindBy(name="btnLogin") WebElement login; public Guru99Login(WebDriver driver){ this.driver = driver; //This initElements method will create all WebElements PageFactory.initElements(driver, this); } //Set user name in textbox public void setUserName(String strUserName){ user99GuruName.sendKeys(strUserName); } //Set password in password textbox public void setPassword(String strPassword){ password99Guru.sendKeys(strPassword); } //Click on login button public void clickLogin(){ login.click(); } //Get the title of Login Page public String getLoginTitle(){ return titleText.getText(); } /** * This POM method will be exposed in test case to login in the application * @param strUserName * @param strPasword * @return */ public void loginToGuru99(String strUserName,String strPasword){ //Fill user name this.setUserName(strUserName); //Fill password this.setPassword(strPasword); //Click Login button this.clickLogin(); } }
Strona główna Guru99 z fabryką stron
package PageFactory; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class Guru99HomePage { WebDriver driver; @FindBy(xpath="//table//tr[@class='heading3']") WebElement homePageUserName; public Guru99HomePage(WebDriver driver){ this.driver = driver; //This initElements method will create all WebElements PageFactory.initElements(driver, this); } //Get the User name from Home Page public String getHomePageDashboardUserName(){ return homePageUserName.getText(); } }
Guru99 TestCase z koncepcją Page Factory
package test; import java.util.concurrent.TimeUnit; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; import org.testng.Assert; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; import PageFactory.Guru99HomePage; import PageFactory.Guru99Login; public class Test99GuruLoginWithPageFactory { String driverPath = "C:\\geckodriver.exe"; WebDriver driver; Guru99Login objLogin; Guru99HomePage objHomePage; @BeforeTest public void setup(){ System.setProperty("webdriver.gecko.driver", driverPath); driver = new FirefoxDriver(); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); driver.get("https://demo.guru99.com/V4/"); } /** * This test go to https://demo.guru99.com/V4/ * Verify login page title as guru99 bank * Login to application * Verify the home page using Dashboard message */ @Test(priority=0) public void test_Home_Page_Appear_Correct(){ //Create Login Page object objLogin = new Guru99Login(driver); //Verify login page title String loginPageTitle = objLogin.getLoginTitle(); Assert.assertTrue(loginPageTitle.toLowerCase().contains("guru99 bank")); //login to application objLogin.loginToGuru99("mgr123", "mgr!23"); // go the next page objHomePage = new Guru99HomePage(driver); //Verify home page Assert.assertTrue(objHomePage.getHomePageDashboardUserName().toLowerCase().contains("manger id : mgr123")); } }
Kompletna struktura projektu będzie wyglądać jak na diagramie:
Fabryka AjaxElementLocator
Fabryka AjaxElementLocator to koncepcja leniwego ładowania PageFactory w Selenium. Służy do znajdowania elementów sieciowych tylko wtedy, gdy elementy są używane w dowolnej operacji. Przypisuje limit czasu dla WebElements do klasy strony obiektu. Jedną z kluczowych zalet korzystania ze wzorca PageFactory w Selenium jest klasą AjaxElementLocatorFactory.
Tutaj, gdy operacja jest wykonywana na elemencie, oczekiwanie na jego widoczność rozpoczyna się dopiero od tego momentu. Jeśli element nie zostanie znaleziony w podanym przedziale czasu, Przypadek testowy wykonanie zgłosi wyjątek „NoSuchElementException”.
Podsumowanie
- Model obiektowy strony w Selenium WebDriver to wzorzec projektowy repozytorium obiektów.
- Selenium Model obiektowy strony tworzy nasz kod testowy, który można utrzymać i ponownie wykorzystać.
- Page Factory to zoptymalizowany sposób tworzenia repozytorium obiektów w koncepcji frameworka Page Object Model.
- AjaxElementLocatorFactory to koncepcja leniwego ładowania w Page Factory – wzorcu projektowym obiektu strony, który identyfikuje WebElements tylko wtedy, gdy są używane w dowolnej operacji.
Pobierz Selenium Pliki projektu dla wersji demonstracyjnej w tym samouczku