Page Object Model and Page Factory in Selenium Using Java (original) (raw)

Last Updated : 18 May, 2026

Page Object Model (POM) and Page Factory are design patterns used to improve the structure and maintainability of test automation code. They help organize web elements and actions while keeping test scripts clean and reusable.

Implementing Page Object Model (POM) in Selenium

POM implementation involves creating separate classes for each page and using them in test scripts to achieve better structure and reusability.

Step 1: Set Up Eclipse Project

Create a Maven project and add required dependencies for Selenium and TestNG.

org.seleniumhq.selenium selenium-java 4.25.0 org.testng testng 7.10.2 test

`

Step 2: Create Package for Page Objects

Create a package to store all page classes.

Step 3: Create a Page Class

Create a class representing the login page and define its elements and actions.

package pages;

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

public class LoginPage { private WebDriver driver; private final String url = "https://www.saucedemo.com/";

// Locators
private By usernameField = By.id("user-name");
private By passwordField = By.id("password");
private By loginButton = By.id("login-button");
private By errorMessage = By.cssSelector("h3[data-test='error']");

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

// Navigate to login page
public void navigateTo() {
    if (!driver.getCurrentUrl().equals(url)) {
        driver.get(url);
    }
}

// Perform login action
public void login(String username, String password) {
    driver.findElement(usernameField).sendKeys(username);
    driver.findElement(passwordField).sendKeys(password);
    driver.findElement(loginButton).click();
}

// Get error message (for invalid login)
public String getErrorMessage() {
    return driver.findElement(errorMessage).getText();
}

}

`

Step 4: Create Package for Test Classes

Create a separate package for test scripts.

Step 5: Create a Test Class

Create a test class to execute test cases using the page class.

package 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 pages.LoginPage;

public class LoginPageTest { private WebDriver driver; private LoginPage loginPage;

@BeforeMethod
public void setUp() {
    System.setProperty("webdriver.chrome.driver", "C:\\Users\\path of chromedriver\\drivers\\chromedriver.exe");
    driver = new ChromeDriver();
    loginPage = new LoginPage(driver);
}

@Test
public void testValidLogin() {
    loginPage.navigateTo();
    loginPage.login("standard_user", "secret_sauce");
    
    // Verify successful login by checking URL
    String expectedUrl = "https://www.saucedemo.com/inventory.html";
    Assert.assertEquals(driver.getCurrentUrl(), expectedUrl, "Login failed: URL mismatch");
}

@Test
public void testInvalidLogin() {
    loginPage.navigateTo();
    loginPage.login("invalid_user", "wrong_password");
    
    // Verify error message
    String expectedError = "Epic sadface: Username and password do not match any user in this service";
    Assert.assertEquals(loginPage.getErrorMessage(), expectedError, "Error message mismatch");
}

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

}

`

Step 6: Run Your Tests

Run the test class and verify the output.

Screenshot-2025-07-18-163227

Page Object Model Output

Page Factory in Selenium

Page Factory is an extension of the Page Object Model (POM) that simplifies the initialization of web elements using built-in Selenium support. It reduces boilerplate code and improves the readability and maintainability of test automation scripts.

Implementing Page Factory in Selenium

Page Factory simplifies the implementation of Page Object Model (POM) by using annotations to initialize web elements. It reduces code complexity and improves readability.

Step 1: Create Page Factory Class

Create a class (LoginPageFactory) inside the pages package to define elements and actions.

package pages;

import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory;

public class LoginPageFactory { private WebDriver driver; private final String url = "https://www.saucedemo.com/";

// Web elements using @FindBy
@FindBy(id = "user-name")
private WebElement usernameField;

@FindBy(id = "password")
private WebElement passwordField;

@FindBy(id = "login-button")
private WebElement loginButton;

@FindBy(css = "h3[data-test='error']")
private WebElement errorMessage;

// Constructor
public LoginPageFactory(WebDriver driver) {
    this.driver = driver;
    PageFactory.initElements(driver, this);
}

// Navigate to login page
public void navigateTo() {
    if (!driver.getCurrentUrl().equals(url)) {
        driver.get(url);
    }
}

// Perform login action
public void login(String username, String password) {
    usernameField.sendKeys(username);
    passwordField.sendKeys(password);
    loginButton.click();
}

// Get error message (for invalid login)
public String getErrorMessage() {
    return errorMessage.getText();
}

}

`

Step 2: Create Test Class

Create a test class (LoginPageFactoryTest) to execute test cases using the Page Factory class.

package pages;

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;

public class LoginPageFactoryTest { private WebDriver driver; private LoginPageFactory loginPage;

@BeforeMethod
public void setUp() {
    System.setProperty("webdriver.chrome.driver", "C:\\Users\\change the path of the chromedriver\\drivers\\chromedriver.exe");
    driver = new ChromeDriver();
    loginPage = new LoginPageFactory(driver);
}

@Test
public void testValidLogin() {
    loginPage.navigateTo();
    loginPage.login("standard_user", "secret_sauce");
    
    // Verify successful login by checking URL
    String expectedUrl = "https://www.saucedemo.com/inventory.html";
    Assert.assertEquals(driver.getCurrentUrl(), expectedUrl, "Login failed: URL mismatch");
}

@Test
public void testInvalidLogin() {
    loginPage.navigateTo();
    loginPage.login("invalid_user", "wrong_password");
    
    // Verify error message
    String expectedError = "Epic sadface: Username and password do not match any user in this service";
    Assert.assertEquals(loginPage.getErrorMessage(), expectedError, "Error message mismatch");
}

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

}

`

Step 3: Execute Tests

Run the test class and verify the results.

**Output: The image below shows the successful execution of Page Factory test cases in Selenium.

output-of-page-factory-using-selenium

Output of Page Factory Using Selenium

Common WebDriver Setup Using Base Class

In the current POM and Page Factory implementation, WebDriver setup, browser initialization, and teardown are repeated in every test class.

1. BaseTest Class Implementation

This BaseTest class handles common browser setup and teardown operations to avoid repetition across test classes.

C++ `

public class BaseTest {

WebDriver driver;

@BeforeMethod
public void setUp() {
    driver = new ChromeDriver();
    driver.manage().window().maximize();
    driver.get("https://www.saucedemo.com/");
}

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

}

`

2. Usage in POM Test Class

This test class reuses the BaseTest setup, keeping only the test logic and improving readability.

C++ `

public class LoginTest extends BaseTest {

@Test
public void testLogin() {
    LoginPage login = new LoginPage(driver);
    login.login("standard_user", "secret_sauce");
}

}

`

3. Usage in Page Factory Test Class

This class also inherits the common setup, ensuring consistency and reducing code duplication.

C++ `

public class LoginPageFactoryTest extends BaseTest {

@Test
public void testLogin() {
    LoginPageFactory login = new LoginPageFactory(driver);
    login.login("standard_user", "secret_sauce");
}

}

`

Advantages of the Page Object Model

The Page Object Model enhances test automation by improving code organization, reusability, and maintainability through clear separation of test logic and UI elements.

Limitations of Page Object Model (POM) and Page Factory

Although POM and Page Factory improve test structure and maintainability, they also come with certain limitations that should be considered before implementation.

Page Object Model Vs Page Factory in Selenium

Here are the differences between Page Object Model and Page Factory in Selenium.

Aspect Page Object Model (POM) Page Factory
Initialization Uses traditional methods to initialize web elements. Utilizes PageFactory.initElements for initializing web elements.
Element Locators Web elements are typically located using methods like findElement. Web elements are defined using @FindBy annotations.
Code Readability Can be less concise due to manual element initialization. More concise and cleaner due to annotation-based element definitions.
Performance Web elements are loaded when the page class is instantiated. Lazy initialization; elements are loaded only when they are used.
Ease of Maintenance Requires manual updates to element locators and initialization. Easier to maintain with annotations and centralized initialization.
Syntax Standard Java syntax for defining and interacting with web elements. Uses annotations (@FindBy) to define element locators.
Error Handling Errors in element locating are more immediately visible. May defer errors until elements are actually interacted with.
Test Script Structure Typically requires more boilerplate code for element definitions. Reduces boilerplate with annotation-based element initialization.
Use Case Suitable for projects where explicit control over element initialization is needed. Ideal for projects requiring cleaner and more concise code with annotation support.