Chào các bạn, đây là phiên bản cập nhật cho bài viết về Page Object Model (POM) và PageFactory, phù hợp với các phiên bản Selenium mới nhất hiện nay (Selenium 4.x trở lên). Vào thời điểm 2026, Selenium đã có nhiều cải tiến mạnh mẽ giúp code gọn gàng và ổn định hơn.
- Sử dụng
Durationthay choTimeUnit(đã cũ). - Giới thiệu Selenium Manager (tự động quản lý driver, không cần
System.setProperty). - Tối ưu hóa Code với Fluent Interface.
- Sử dụng
WebDriverWait(Explicit Wait) chuẩn chỉnh hơn.
1. Cấu trúc Project
Chúng ta sẽ chia project thành các phần rõ ràng theo mô hình POM:
- Pages: Chứa các class đại diện cho từng trang (LoginPage, HomePage...), nơi khai báo Element và Action.
- Tests: Chứa các Test Case thực thi.
2. Class LoginPage (Trang Đăng Nhập)
Sử dụng @FindBy để định danh phần tử và PageFactory.initElements để khởi tạo.
package vn.haibgit.pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.CacheLookup;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class LoginPage {
private WebDriver driver;
// Constructor: Khởi tạo PageFactory
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
// Định nghĩa Element với @FindBy
@FindBy(name = "uid")
@CacheLookup // Cache element nếu nó không thay đổi để tăng tốc độ
private WebElement txtUserName;
@FindBy(name = "password")
@CacheLookup
private WebElement txtPassword;
@FindBy(name = "btnLogin")
@CacheLookup
private WebElement btnLogin;
@FindBy(name = "btnReset")
private WebElement btnReset;
// --- Action Methods ---
public void setUserName(String name) {
txtUserName.clear(); // Best practice: Clear trước khi nhập
txtUserName.sendKeys(name);
}
public void setPassword(String password) {
txtPassword.clear();
txtPassword.sendKeys(password);
}
// Trả về HomePage sau khi login thành công (Fluent Interface)
public HomePage clickLogin() {
btnLogin.click();
return new HomePage(driver);
}
/**
* Phương thức Login gộp cho tiện sử dụng
*/
public HomePage login(String userName, String password) {
setUserName(userName);
setPassword(password);
return clickLogin();
}
}
3. Class HomePage (Trang Chủ)
Ở đây chúng ta thêm xử lý đợi thông minh (Explicit Wait) để đảm bảo trang đã load xong.
package vn.haibgit.pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.CacheLookup;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration; // Import mới cho Selenium 4+
public class HomePage {
private WebDriver driver;
@FindBy(className = "heading3")
@CacheLookup
private WebElement txtWelcome;
public HomePage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public boolean isPageLoaded() {
// Sử dụng WebDriverWait với Duration (thay thế cho int/TimeUnit cũ)
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
try {
// Đợi cho element hiển thị rõ ràng
wait.until(ExpectedConditions.visibilityOf(txtWelcome));
String welcomeText = txtWelcome.getText();
return welcomeText.contains("Welcome To Manager's Page of Guru99 Bank");
} catch (Exception e) {
return false;
}
}
}
4. Class TestPOM (Viết Test Case)
Lưu ý quan trọng: TimeUnit.SECONDS đã bị loại bỏ/deprecated trong các bản mới. Chúng ta chuyển sang
dùng Duration.ofSeconds(...).
package vn.haibgit.tests;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import vn.haibgit.pages.HomePage;
import vn.haibgit.pages.LoginPage;
import java.time.Duration;
public class TestPOM {
private WebDriver driver;
// URL demo (có thể thay đổi tùy thời điểm)
private String url = "http://demo.guru99.com/v4/";
@BeforeMethod
public void setUp() {
// Selenium 4.x+: Không cần System.setProperty("webdriver.chrome.driver", ...)
// Selenium Manager sẽ tự động tải driver tương thích.
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get(url);
// CẬP NHẬT QUAN TRỌNG: Sử dụng Duration thay vì TimeUnit
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
}
@Test
public void testLoginSuccess() {
LoginPage loginPage = new LoginPage(driver);
// Thực hiện login và nhận về HomePage object
HomePage homePage = loginPage.login("mngr588662", "YvUzUqa");
// Verify kết quả
Assert.assertTrue(homePage.isPageLoaded(), "Đăng nhập thất bại hoặc trang chủ chưa tải xong!");
}
@AfterMethod
public void tearDown() {
if (driver != null) {
driver.quit();
}
}
}
5. Giải thích các thay đổi quan trọng (2026)
5.1. Duration thay cho TimeUnit
Trong các phiên bản Selenium cũ, chúng ta viết:
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
Nhưng hiện tại, syntax chuẩn là: driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
5.2. Selenium Manager
Bạn không cần phải tải thủ công chromedriver.exe và set path nữa. Thư viện Selenium sẽ tự động phát
hiện trình duyệt Chrome trên máy và tải driver phù hợp nhất. Code gọn hơn rất nhiều!
5.3. Tại sao dùng @CacheLookup?
Vẫn giữ nguyên giá trị: Giúp Selenium lưu trữ element trong bộ nhớ cache sau lần tìm kiếm đầu tiên. Cực kỳ hữu ích cho các phần tử tĩnh (Logo, Menu, Input field cố định) giúp tăng tốc độ test.
Chúc các bạn áp dụng thành công Page Object Model vào dự án của mình!
0 comments:
Post a Comment