Page Object Model selenium 2026

Bài viết này hướng dẫn cách triển khai Page Object Model (POM) thuần (sử dụng By locators) thay vì dùng PageFactory, cập nhật theo chuẩn Selenium mới nhất năm 2026.

Tại sao nên dùng POM ("thuần") thay vì PageFactory?
Mặc dù PageFactory ('@FindBy') rất phổ biến, nhưng trong các dự án lớn, việc tự quản lý locator bằng đối tượng By giúp kiểm soát tốt hơn các vấn đề về StaleElementReferenceException và linh hoạt hơn khi xử lý các phần tử động (Dynamic Elements).

1. Tạo Class LoginPage (Quản lý đối tượng trang)

Thay đổi so với code cũ:

  • Dùng Encapsulation (private fields) để bảo vệ locator.
  • Hàm trả về đối tượng (return this) để hỗ trợ Chaining Method (viết code test liền mạch hơn).
package vn.haibgit.pages;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;

public class LoginPage {
    
    private WebDriver driver;

    // 1. Khai báo Locators (Nên dùng private để đóng gói)
    private By txtUsername = By.name("uid");
    private By txtPassword = By.name("password");
    private By btnLogin = By.name("btnLogin");
    private By btnReset = By.name("btnReset");

    // 2. Constructor
    public LoginPage(WebDriver driver) {
        this.driver = driver;
    }

    // 3. Các Action Methods
    public LoginPage enterUsername(String username) {
        // Tốt nhất nên clear text trước khi sendKeys
        driver.findElement(txtUsername).clear();
        driver.findElement(txtUsername).sendKeys(username);
        return this; // Trả về chính nó để có thể gọi tiếp (Fluent Interface)
    }

    public LoginPage enterPassword(String password) {
        driver.findElement(txtPassword).clear();
        driver.findElement(txtPassword).sendKeys(password);
        return this;
    }

    public void clickLogin() {
        driver.findElement(btnLogin).click();
        // Sau khi click login có thể trả về HomePage object nếu cần
    }

    // Hàm Wrapper xử lý trọn vẹn 1 flow
    public void login(String username, String password) {
        this.enterUsername(username);
        this.enterPassword(password);
        this.clickLogin();
    }
}

2. Tạo Test Class (Thực thi kiểm thử)

Cập nhật quan trọng 2026:

  • Không cần set path cho driver: Selenium Manager tự động lo liệu việc download chromedriver.
  • Dùng Duration: Class TimeUnit đã cũ, hãy 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.LoginPage;
import java.time.Duration;

public class LoginTest {

    private WebDriver driver;

    @BeforeMethod
    public void setUp() {
        // Selenium 4.x+: Tự động tải driver, không cần System.setProperty(...)
        driver = new ChromeDriver();
        
        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10)); // Syntax mới
        
        driver.get("http://demo.guru99.com/v4/");
    }

    @Test
    public void testValidLogin() {
        // Khởi tạo Page Object
        LoginPage loginPage = new LoginPage(driver);

        // Thực hiện hành động login
        // Cách viết Fluent: loginPage.enterUsername("user").enterPassword("pass").clickLogin();
        // Hoặc dùng hàm wrapper:
        loginPage.login("mngr588662", "YvUzUqa");

        // Verify title (Ví dụ)
        String expectedTitle = "Guru99 Bank Manager HomePage";
        String actualTitle = driver.getTitle();
        Assert.assertEquals(actualTitle, expectedTitle, "Tiêu đề trang không khớp!");
    }

    @AfterMethod
    public void tearDown() {
        if (driver != null) {
            driver.quit();
        }
    }
}

Việc áp dụng POM giúp code sạch sẽ, dễ bảo trì và dễ mở rộng (Scalability) hơn rất nhiều so với việc viết code Spag

0 comments:

Post a Comment