โมเดลวัตถุหน้าและโรงงานใน Selenium

⚡ สรุปอย่างชาญฉลาด

โมเดลวัตถุหน้าและโรงงานหน้าใน Selenium กำหนดรูปแบบการออกแบบที่มีโครงสร้างสำหรับการสร้างกรอบการทำงานอัตโนมัติสำหรับการทดสอบที่แข็งแกร่งและบำรุงรักษาได้ โดยเน้นการสร้างคลาสเฉพาะหน้าซึ่งรวม WebElements และพฤติกรรมของพวกมันไว้ด้วยกัน ซึ่งจะช่วยลดความซ้ำซ้อนและปรับปรุงความสามารถในการอ่านและปรับขนาดของ Selenium สคริปต์ทดสอบ

  • แนวคิดหลัก: หน้าแอปพลิเคชันแต่ละหน้าจะสอดคล้องกับ Page Class เฉพาะซึ่งประกอบด้วยทั้ง WebElements และการดำเนินการที่ดำเนินการกับองค์ประกอบเหล่านั้น ช่วยให้แยกโครงสร้าง UI และตรรกะการทดสอบออกจากกันได้อย่างชัดเจน
  • จุดเน้นในการดำเนินการ: POM ส่งเสริมการจัดการองค์ประกอบแบบใช้ซ้ำและรวมศูนย์ การปรับเปลี่ยนองค์ประกอบของหน้าต้องมีการอัปเดตในคลาสเดียวเท่านั้นแทนที่จะเป็นสคริปต์หลายตัว
  • ข้อได้เปรียบด้านการออกแบบ: โมเดลนี้รับประกันว่าที่เก็บวัตถุจะสะอาดขึ้น เป็นโมดูล และไม่ขึ้นอยู่กับเครื่องมือ ซึ่งสามารถบูรณาการกับกรอบงาน เช่น TestNG, JUnit, Cucumber, หรือ JBehave
  • อนุสัญญาการตั้งชื่อ: วิธีการภายในคลาสหน้าจะต้องสะท้อนการดำเนินการ UI จริง (เช่น gotoHomePage()) เสริมสร้างความชัดเจนด้านความหมายในเวิร์กโฟลว์อัตโนมัติ
  • โครงสร้างที่ได้รับการปรับปรุง: Page Factory ปรับปรุง POM โดยใช้ @FindBy คำอธิบายประกอบและ PageFactory.initElements() สำหรับการเริ่มต้น WebElement อัตโนมัติ ขจัดความซ้ำซาก findElement โทร
  • การเพิ่มประสิทธิภาพการทำงาน: AjaxElementLocatorFactory แนะนำการโหลดแบบขี้เกียจ—องค์ประกอบจะถูกระบุตำแหน่งเฉพาะเมื่อเข้าถึงเท่านั้น—ปรับปรุงประสิทธิภาพในการดำเนินการและจัดการพฤติกรรมของหน้าไดนามิกได้อย่างสวยงาม
  • ผล: แนวทางแบบรวมศูนย์ส่งผลให้สถาปัตยกรรมการทดสอบอัตโนมัติสามารถบำรุงรักษา อ่านได้ และปรับขนาดได้สอดคล้องกับสมัยใหม่ Selenium การปฏิบัติ

โมเดลออบเจ็กต์เพจ

Page Object Model คืออะไร และมีส่วนประกอบหลักอะไรบ้าง

โมเดลออบเจ็กต์เพจ (POM) เป็นรูปแบบการออกแบบที่นิยมใช้กันในการทดสอบระบบอัตโนมัติ ซึ่งสร้าง Object Repository สำหรับองค์ประกอบ UI บนเว็บ ข้อดีของโมเดลนี้คือช่วยลดความซ้ำซ้อนของโค้ดและปรับปรุงการบำรุงรักษาการทดสอบ

ภายใต้โมเดลนี้ สำหรับแต่ละหน้าเว็บในแอปพลิเคชัน ควรมีคลาส Page ที่สอดคล้องกัน คลาส Page นี้จะระบุ WebElements ของหน้าเว็บนั้น และยังประกอบด้วยเมธอด Page ที่ดำเนินการกับ WebElements เหล่านั้นด้วย ชื่อของเมธอดเหล่านี้ควรกำหนดตามงานที่กำลังดำเนินการอยู่ เช่น หากตัวโหลดกำลังรอให้เกตเวย์การชำระเงินปรากฏขึ้น ชื่อเมธอด POM อาจเป็น waitForPaymentScreenDisplay()

ส่วนประกอบหลักของโมเดลวัตถุหน้า

  • คลาสหน้า: แสดงแต่ละหน้าเว็บเป็นคลาสที่แยกจากกัน
  • ตัวระบุตำแหน่ง: ระบุองค์ประกอบเว็บโดยใช้ ID, XPath หรือตัวเลือก CSS
  • วิธีการ: ประกอบด้วยการดำเนินการหรือการดำเนินการที่ดำเนินการบนองค์ประกอบ .page
  • การนำกลับมาใช้ใหม่: Promoการนำรหัส TES มาใช้ซ้ำและการบำรุงรักษาที่ง่ายขึ้นในทุกการทดสอบ
  • การแยกข้อกังวล: รักษาโครงสร้างหน้าให้เป็นอิสระจากตรรกะการทดสอบเพื่อการจัดระเบียบที่ดีขึ้น

โมเดลออบเจ็กต์เพจ

ทำไมต้องใช้โมเดลออบเจ็กต์เพจ?

การเริ่มต้นระบบอัตโนมัติ UI ใน Selenium ไดรเวอร์เว็บ ไม่ใช่เรื่องยาก คุณเพียงแค่ต้องค้นหาองค์ประกอบและดำเนินการกับมัน

พิจารณาสคริปต์ง่ายๆ นี้เพื่อเข้าสู่ระบบเว็บไซต์

โมเดลออบเจ็กต์เพจ

อย่างที่คุณเห็น สิ่งที่เราทำคือการค้นหาองค์ประกอบและเติมค่าให้กับองค์ประกอบเหล่านั้น

นี่เป็นสคริปต์ที่ใช้เวลานานและมักเกิดข้อผิดพลาด ในตอนแรกดูเหมือนจะง่าย แต่เมื่อชุดทดสอบขยายตัว การจัดการการเปลี่ยนแปลงองค์ประกอบก็กลายเป็นเรื่องยาก แต่เมื่อเวลาผ่านไป ชุดทดสอบก็จะขยายใหญ่ขึ้น เมื่อคุณเพิ่มบรรทัดในโค้ดมากขึ้นเรื่อยๆ สิ่งต่างๆ ก็จะยากขึ้น

ปัญหาหลักในการบำรุงรักษาสคริปต์ก็คือ หากมีสคริปต์ที่แตกต่างกัน 10 สคริปต์ใช้องค์ประกอบของหน้าเดียวกัน หากมีการเปลี่ยนแปลงในองค์ประกอบนั้น คุณจะต้องเปลี่ยนสคริปต์ทั้ง 10 สคริปต์ ซึ่งใช้เวลานานและเกิดข้อผิดพลาดได้ง่าย

วิธีที่ดีกว่าในการบำรุงรักษาสคริปต์คือการสร้างไฟล์คลาสแยกต่างหากที่จะค้นหาองค์ประกอบเว็บ เติมข้อมูล หรือตรวจสอบองค์ประกอบเหล่านั้น คลาสนี้สามารถนำกลับมาใช้ซ้ำในสคริปต์ทดสอบหลายตัวที่โต้ตอบกับองค์ประกอบเดียวกันได้ ในอนาคต หากมีการเปลี่ยนแปลงองค์ประกอบเว็บ เราจำเป็นต้องทำการเปลี่ยนแปลงในไฟล์คลาสเพียงไฟล์เดียว ไม่ใช่สคริปต์ 10 สคริปต์ที่แตกต่างกัน

วิธีการนี้เรียกว่า Page Object Model in Selenium. ช่วยให้โค้ดอ่านง่ายขึ้น บำรุงรักษาง่ายขึ้น และนำกลับมาใช้ซ้ำได้

 โมเดลออบเจ็กต์เพจ

👉 สมัครเรียนสดฟรี Selenium โครงการ

ข้อดีของ POM

  1. รูปแบบการออกแบบวัตถุในหน้าเพจระบุว่าการดำเนินการและโฟลว์ใน UI ควรแยกออกจากการตรวจสอบ แนวคิดนี้ทำให้โค้ดของเราสะอาดขึ้นและเข้าใจง่ายขึ้น
  2. ประโยชน์ประการที่สองคือ ที่เก็บอ็อบเจ็กต์นั้นเป็นอิสระจากกรณีทดสอบ ดังนั้นเราจึงสามารถใช้ที่เก็บอ็อบเจ็กต์เดียวกันสำหรับวัตถุประสงค์ที่แตกต่างกันด้วยเครื่องมือที่แตกต่างกัน ตัวอย่างเช่น เราสามารถผสานรวม Page Object Model เข้ากับ Selenium สีสดสวย TestNG/JUnit สำหรับการทำงาน การทดสอบ และในเวลาเดียวกันกับ JBehave/Cucumber สำหรับการทดสอบการยอมรับ
  3. Code มีประสิทธิภาพและเหมาะสมยิ่งขึ้นเนื่องจากมีการนำเมธอดของเพจมาใช้ซ้ำในคลาส POM
  4. วิธีการได้รับชื่อที่สมจริงมากขึ้นซึ่งสามารถแมปไปยังการดำเนินการที่เกิดขึ้นใน UI ได้อย่างง่ายดาย เช่น หากหลังจากคลิกปุ่มแล้วเราลงจอดบนหน้าแรก ชื่อวิธีการจะเป็นเช่น 'gotoHomePage()'

วิธีการนำ POM มาใช้ Selenium?

PLog ง่ายๆ ในโครงสร้างพื้นฐานของกรอบงาน Page Object Model โดยที่ whereManagereIDElements ของ AUT และวิธีการที่ดำเนินการกับองค์ประกอบเว็บเหล่านี้จะถูกเก็บรักษาไว้ภายในไฟล์ clog งานเช่นการตรวจสอบควรแยกออกจากกันเป็นส่วนหนึ่งของวิธีการทดสอบ

ปรับใช้ POM

ตัวอย่างที่สมบูรณ์

กรณีทดสอบ: ไปที่ Guru99 เว็บไซต์สาธิต

ขั้นตอนที่ 1) ไปที่ Guru99 เว็บไซต์สาธิต

ปรับใช้ POM

ขั้นตอนที่ 2) บนหน้าแรก ตรวจสอบว่าข้อความ “Guru"ธนาคาร 99" มีอยู่

ปรับใช้ POM

ขั้นตอนที่ 3) เข้าสู่ระบบแอปพลิเคชัน

ปรับใช้ POM

ขั้นตอนที่ 4) ตรวจสอบว่าหน้าแรกมีข้อความเป็น “Manger Id: demo”

ปรับใช้ POM

ในตัวอย่างนี้ เราจะจัดการกับสองหน้า:

  1. เข้าสู่ระบบหน้า
  2. หน้าแรก (แสดงเมื่อคุณเข้าสู่ระบบ)

ดังนั้นเราจึงสร้าง POM 2 อันขึ้นมา Selenium ชั้นเรียน

Guru99 หน้าเข้าสู่ระบบ 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 the 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 allows the test case to perform the login operation
     * @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();        
    }
}

Guru99 หน้าแรก POM ใน 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 POM แบบง่ายใน Selenium กรณีทดสอบ

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("manager id : mgr123"));
    }

Page Factory คืออะไร Selenium?

หน้าโรงงานใน Selenium เป็นแนวคิดเฟรมเวิร์ก Page Object Model แบบ inbuilt สำหรับ Selenium WebDriver ที่ปรับปรุงความสามารถในการบำรุงรักษาโดยลดการค้นหาองค์ประกอบซ้ำๆ โดยใช้คำอธิบายประกอบ ไม่ใช่ความเร็วในการทำงาน ใช้สำหรับการเริ่มต้นอ็อบเจ็กต์ Page หรือสร้างอินสแตนซ์ของอ็อบเจ็กต์ Page เอง นอกจากนี้ยังใช้สำหรับการเริ่มต้นองค์ประกอบคลาส Page โดยไม่ต้องใช้ "FindElement/s"

ในที่นี้ เรายังปฏิบัติตามแนวคิดของการแยก Page Object Repository และ Test Methods นอกจากนี้ด้วยความช่วยเหลือของคลาส PageFactory ใน Seleniumเราใช้คำอธิบายประกอบ @FindBy เพื่อค้นหา WebElement เราใช้วิธี initElements เพื่อเริ่มต้นองค์ประกอบเว็บ

เพจ โรงงาน อิน Selenium

@FindBy ยอมรับได้ tagName, PartialLinkText, ชื่อ, linkText, id, css, className, xpath เป็นคุณลักษณะ

ลองดูตัวอย่างเดียวกันกับข้างบนโดยใช้ Page Factory

Guru99 หน้าเข้าสู่ระบบด้วย 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();           
    }
}

Guru99 หน้าแรกด้วย 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 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 กรณีทดสอบด้วยแนวคิด 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("manager id : mgr123"));
    }
}

โครงสร้างโครงการที่สมบูรณ์จะมีลักษณะเหมือนแผนภาพ:

หน้าโรงงานใน Selenium

โรงงาน AjaxElementLocator

โรงงาน AjaxElementLocator เป็นแนวคิดการโหลดแบบ Lazy Loading ของ PageFactory ใน Seleniumใช้เพื่อค้นหาองค์ประกอบเว็บเฉพาะเมื่อองค์ประกอบนั้นถูกใช้ในการดำเนินการใดๆ เท่านั้น โดยจะกำหนดเวลาหมดเวลาสำหรับ WebElements ให้กับคลาสเพจของอ็อบเจ็กต์ ข้อดีหลักประการหนึ่งของการใช้รูปแบบ PageFactory ใน Selenium เป็นคลาส AjaxElementLocatorFactory

ในกรณีนี้ เมื่อดำเนินการกับองค์ประกอบ การรอให้องค์ประกอบนั้นปรากฏจะเริ่มตั้งแต่วินาทีนั้นเท่านั้น หากไม่พบองค์ประกอบนั้นภายในช่วงเวลาที่กำหนด กรณีทดสอบ การดำเนินการจะส่งข้อยกเว้น 'NoSuchElementException'

โรงงานตัวระบุตำแหน่ง AjaxElement

ตัวอย่างเช่น:

AjaxElementLocatorFactory factory = new AjaxElementLocatorFactory(driver, 10);
PageFactory.initElements(factory, this);

ดาวน์โหลด Selenium ไฟล์โครงการสำหรับการสาธิตในบทช่วยสอนนี้

คำถามที่พบบ่อย

Page Object Model เป็นรูปแบบการออกแบบที่...tracแยกองค์ประกอบของเว็บเพจ ts ออกเป็นคลาสต่างๆ วิธีนี้ช่วยลดความซับซ้อนของการทำงานอัตโนมัติโดยการแยกการโต้ตอบกับ UI ออกจากตรรกะการทดสอบ ส่งเสริมความชัดเจน ความสามารถในการขยายขนาด และลดการเขียนโค้ดซ้ำซ้อน

In SeleniumPOM แสดงหน้าเว็บแต่ละหน้าเป็นคลาสเฉพาะที่ประกอบด้วยตัวระบุตำแหน่งและแอคชันต่างๆ คลาสนี้ห่อหุ้มองค์ประกอบ UI ไว้ ทำให้สคริปต์ทดสอบยังคงเป็นอิสระจากการเปลี่ยนแปลงโครงสร้างหน้าเว็บพื้นฐาน

POM ไม่ใช่กรอบงานแบบสแตนด์อโลน แต่เป็นรูปแบบการออกแบบ สามารถผสานรวมเข้ากับกรอบงานอัตโนมัติใดๆ ก็ได้ เพื่อจัดโครงสร้างการทดสอบอย่างมีประสิทธิภาพ มั่นใจได้ถึงการจัดระเบียบที่ดีขึ้น การนำกลับมาใช้ใหม่ และการบำรุงรักษาที่ดีขึ้น

POM คือหลักการออกแบบที่แต่ละหน้าเว็บถูกสร้างแบบจำลองเป็นคลาสที่มีตัวระบุตำแหน่งและเมธอดที่กำหนดไว้ หลักการนี้แยกตรรกะการทดสอบออกจากองค์ประกอบ UI เพื่อเพิ่มความสามารถในการอ่าน ความสามารถในการปรับขนาด และการบำรุงรักษาในระยะยาว

POM กำหนดโครงสร้างการออกแบบสำหรับ abs ของหน้าtracในขณะที่ Page Factory ให้คำอธิบายประกอบและเมธอด (@FindBy) เพื่อการเริ่มต้นองค์ประกอบเว็บอย่างมีประสิทธิภาพ Page Factory คือส่วนเสริมการใช้งานของ POM

POM รวบรวมตัวระบุตำแหน่งองค์ประกอบและการดำเนินการในหน้าไว้ในคลาสเฉพาะ การปรับเปลี่ยน UI ใดๆ จำเป็นต้องมีการอัปเดตในที่เดียวเท่านั้น ช่วยลดการทำงานซ้ำ ปรับปรุงการนำโค้ดกลับมาใช้ใหม่ และเร่งการบำรุงรักษาการทดสอบ

ใช่ เครื่องสร้างการทดสอบที่ขับเคลื่อนด้วย AI สามารถสร้างคลาส POM ได้โดยอัตโนมัติโดยการวิเคราะห์ลำดับชั้น UI รักษาการแยกข้อกังวลอย่างมีเหตุผล ขณะเดียวกันก็เร่งการสร้างการทดสอบแบบครบวงจร

POM ส่งเสริมส่วนประกอบการทดสอบแบบแยกส่วนและนำกลับมาใช้ใหม่ได้ ช่วยให้สามารถบูรณาการกับเครื่องมือบำรุงรักษาการทดสอบที่ใช้ AI ซึ่งอัปเดตตัวระบุตำแหน่งอัตโนมัติ ลดความเปราะบางของสคริปต์และค่าใช้จ่ายในการบำรุงรักษา

สรุปโพสต์นี้ด้วย: