โมเดลวัตถุหน้าและโรงงานใน Selenium
โมเดลออบเจ็กต์เพจคืออะไร
โมเดลออบเจ็กต์เพจ (POM) เป็นรูปแบบการออกแบบที่ใช้กันอย่างแพร่หลายในการทดสอบอัตโนมัติที่สร้าง Object Repository สำหรับองค์ประกอบ UI ของเว็บ ข้อดีของโมเดลนี้คือช่วยลดความซ้ำซ้อนของโค้ดและปรับปรุงการบำรุงรักษาการทดสอบ
ภายใต้โมเดลนี้ สำหรับแต่ละหน้าเว็บในแอปพลิเคชัน ควรมีคลาส Page ที่สอดคล้องกัน คลาส Page นี้จะระบุ WebElements ของหน้าเว็บนั้น และยังประกอบด้วยเมธอด Page ที่ดำเนินการกับ WebElements เหล่านั้นด้วย ชื่อของเมธอดเหล่านี้ควรกำหนดตามงานที่กำลังดำเนินการอยู่ กล่าวคือ หากตัวโหลดกำลังรอให้เกตเวย์การชำระเงินปรากฏขึ้น ชื่อเมธอด POM อาจเป็น waitForPaymentScreenDisplay()
ทำไมต้องใช้โมเดลออบเจ็กต์เพจ?
การเริ่มต้น UI Automation ใน Selenium WebDriver ไม่ใช่เรื่องยาก คุณเพียงแค่ต้องค้นหาองค์ประกอบและดำเนินการกับองค์ประกอบเหล่านั้น
พิจารณาสคริปต์ง่ายๆ นี้เพื่อเข้าสู่เว็บไซต์
อย่างที่คุณเห็น สิ่งที่เราทำคือการค้นหาองค์ประกอบและเติมค่าให้กับองค์ประกอบเหล่านั้น
นี่เป็นสคริปต์ขนาดเล็ก การบำรุงรักษาสคริปต์ดูง่าย แต่เมื่อเวลาผ่านไปชุดทดสอบก็จะเติบโตขึ้น เมื่อคุณเพิ่มบรรทัดในโค้ดของคุณมากขึ้นเรื่อยๆ สิ่งต่างๆ ก็จะกลายเป็นเรื่องยาก
ปัญหาหลักในการบำรุงรักษาสคริปต์ก็คือ หากมีสคริปต์ที่แตกต่างกัน 10 สคริปต์ใช้องค์ประกอบของหน้าเดียวกัน หากมีการเปลี่ยนแปลงในองค์ประกอบนั้น คุณจะต้องเปลี่ยนสคริปต์ทั้ง 10 สคริปต์ ซึ่งใช้เวลานานและเกิดข้อผิดพลาดได้ง่าย
แนวทางที่ดีกว่าในการบำรุงรักษาสคริปต์คือการสร้างไฟล์คลาสแยกต่างหากซึ่งจะค้นหาองค์ประกอบของเว็บ เติมองค์ประกอบเหล่านั้น หรือตรวจสอบองค์ประกอบเหล่านั้น คลาสนี้สามารถนำมาใช้ซ้ำได้ในสคริปต์ทั้งหมดโดยใช้องค์ประกอบนั้น ในอนาคต หากมีการเปลี่ยนแปลงในองค์ประกอบเว็บ เราจำเป็นต้องทำการเปลี่ยนแปลงในไฟล์คลาสเพียง 1 ไฟล์ ไม่ใช่ 10 สคริปต์ที่แตกต่างกัน
วิธีการนี้เรียกว่า Page Object Model in Seleniumช่วยให้โค้ดสามารถอ่านได้ง่ายขึ้น บำรุงรักษาได้ง่ายขึ้น และนำกลับมาใช้ซ้ำได้
ข้อดีของ POM
- รูปแบบการออกแบบวัตถุในหน้าเพจระบุว่าการดำเนินการและโฟลว์ใน UI ควรแยกออกจากการตรวจสอบ แนวคิดนี้ทำให้โค้ดของเราสะอาดขึ้นและเข้าใจง่ายขึ้น
- ประโยชน์ประการที่สองคือที่เก็บวัตถุนั้นไม่ขึ้นอยู่กับกรณีทดสอบ ดังนั้นเราจึงสามารถใช้ที่เก็บวัตถุเดียวกันเพื่อวัตถุประสงค์ที่แตกต่างกันด้วยเครื่องมือที่แตกต่างกัน ตัวอย่างเช่น เราสามารถรวม Page Object Model เข้าไปได้ Selenium สีสดสวย TestNG/JUnit สำหรับการทำงาน การทดสอบ และในเวลาเดียวกันกับ JBehave/Cucumber สำหรับการทดสอบการยอมรับ
- โค้ดน้อยลงและได้รับการปรับปรุงให้เหมาะสมเนื่องจากวิธีการเพจแบบใช้ซ้ำได้ในคลาส POM
- วิธีการได้รับชื่อที่สมจริงมากขึ้นซึ่งสามารถแมปได้อย่างง่ายดายด้วยการดำเนินการที่เกิดขึ้นใน UI เช่น หากหลังจากคลิกปุ่มแล้วเราลงเอยที่หน้าแรก ชื่อวิธีการจะเป็นเช่น 'gotoHomePage()'
จะนำ POM ไปใช้อย่างไร?
POM ง่าย ๆ:
เป็นโครงสร้างพื้นฐานของกรอบงานโมเดลออบเจ็กต์เพจโดยที่องค์ประกอบเว็บทั้งหมดของ AUT และวิธีการที่ดำเนินการบนองค์ประกอบเว็บเหล่านี้จะได้รับการดูแลรักษาภายในไฟล์คลาส งานเช่นการตรวจสอบควรแยกออกจากกันเป็นส่วนหนึ่งของวิธีการทดสอบ
ตัวอย่างที่สมบูรณ์
กรณีทดสอบ: ไปที่เว็บไซต์สาธิต Guru99
ขั้นตอนที่ 1) ไปที่ไซต์สาธิต Guru99
ขั้นตอนที่ 2) ในหน้าแรกให้ตรวจสอบข้อความ “Guru99 Bank” ปรากฏอยู่
ขั้นตอนที่ 3) เข้าสู่ระบบแอปพลิเคชัน
ขั้นตอนที่ 4) ตรวจสอบว่าหน้าแรกมีข้อความเป็น “Manger Id: demo”
นี่คือเรากำลังจัดการกับ 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 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();
}
}
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("manger id : mgr123"));
}
Page Factory คืออะไร Selenium?
หน้าโรงงานใน Selenium เป็นแนวคิดเฟรมเวิร์ก Page Object Model แบบ inbuilt สำหรับ Selenium WebDriver แต่ได้รับการปรับให้เหมาะสมที่สุด ใช้สำหรับการเริ่มต้นออบเจ็กต์เพจหรือเพื่อสร้างอินสแตนซ์ออบเจ็กต์เพจเอง นอกจากนี้ยังใช้เพื่อเริ่มต้นองค์ประกอบคลาสของหน้าโดยไม่ต้องใช้ “FindElement/s”
ในที่นี้ เรายังปฏิบัติตามแนวคิดของการแยก Page Object Repository และ Test Methods นอกจากนี้ด้วยความช่วยเหลือของคลาส PageFactory ใน Seleniumเราใช้คำอธิบายประกอบ @FindBy เพื่อค้นหา WebElement เราใช้วิธี initElements เพื่อเริ่มต้นองค์ประกอบเว็บ
@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 พร้อมเพจแฟคทอรี
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 พร้อมแนวคิด 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"));
}
}
โครงสร้างโครงการที่สมบูรณ์จะมีลักษณะเหมือนแผนภาพ:
โรงงาน AjaxElementLocator
โรงงาน AjaxElementLocator เป็นแนวคิดการโหลดแบบ Lazy Loading ของ PageFactory ใน Seleniumใช้เพื่อระบุองค์ประกอบเว็บเฉพาะในกรณีที่องค์ประกอบนั้นถูกใช้ในการดำเนินการใดๆ เท่านั้น โดยจะกำหนดเวลาหมดเวลาสำหรับ WebElements ให้กับคลาสเพจของอ็อบเจกต์ ข้อดีหลักประการหนึ่งของการใช้รูปแบบ PageFactory ใน Selenium เป็นคลาส AjaxElementLocatorFactory
ที่นี่ เมื่อดำเนินการกับองค์ประกอบ การรอให้องค์ประกอบนั้นมองเห็นได้จะเริ่มตั้งแต่ช่วงเวลานั้นเท่านั้น หากไม่พบองค์ประกอบนั้นในช่วงเวลาที่กำหนด กรณีทดสอบ การดำเนินการจะส่งข้อยกเว้น 'NoSuchElementException'
สรุป
- โมเดลออบเจ็กต์เพจใน Selenium WebDriver เป็นรูปแบบการออกแบบ Object Repository
- Selenium โมเดลออบเจ็กต์เพจสร้างโค้ดทดสอบของเราที่สามารถบำรุงรักษาและนำกลับมาใช้ใหม่ได้
- Page Factory เป็นวิธีที่เหมาะสมที่สุดในการสร้างที่เก็บอ็อบเจ็กต์ในแนวคิดเฟรมเวิร์ก Page Object Model
- AjaxElementLocatorFactory เป็นแนวคิดการโหลดแบบขี้เกียจใน Page Factory ซึ่งเป็นรูปแบบการออกแบบวัตถุของหน้าที่จะระบุ WebElements เฉพาะเมื่อมีการใช้ในการดำเนินการใดๆ เท่านั้น
ดาวน์โหลด Selenium ไฟล์โครงการสำหรับการสาธิตในบทช่วยสอนนี้











