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().

Model obiektu strony

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

Model obiektu strony

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.

Model obiektu strony

Zalety POM

  1. 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.
  2. 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.
  3. Kod staje się mniejszy i zoptymalizowany ze względu na metody stron wielokrotnego użytku w klasach POM.
  4. 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.

Wdrażaj POM

Kompletny przykład

Przypadek testowy: Przejdź do witryny demonstracyjnej Guru99.

Krok 1) Przejdź do witryny demonstracyjnej Guru99

Wdrażaj POM

Krok 2) Sprawdź, czy na stronie głównej znajduje się tekst „Guru99 Bank”.

Wdrażaj POM

Krok 3) Zaloguj się do aplikacji

Wdrażaj POM

Krok 4) Sprawdź, czy strona główna zawiera tekst „Identyfikator menedżera: demo”

Wdrażaj POM

Tutaj mamy do czynienia z 2 stronami

  1. Strona logowania
  2. 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

Fabryka strony w Selenium

@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:

Strona Fabryki w Selenium

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”.

Fabryka lokalizatorów AjaxElement

Podsumowanie

  1. Model obiektowy strony w Selenium WebDriver to wzorzec projektowy repozytorium obiektów.
  2. Selenium Model obiektowy strony tworzy nasz kod testowy, który można utrzymać i ponownie wykorzystać.
  3. Page Factory to zoptymalizowany sposób tworzenia repozytorium obiektów w koncepcji frameworka Page Object Model.
  4. 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