Page Object Model (POM) & Page Factory in Selenium: The Ultimate Guide

Automated testing is crucial for delivering high quality software quickly. However, building and maintaining test automation suites is challenging – 55% of organizations cite the inability to reuse tests across projects as a key limitation. The Page Object Model (POM) pattern tackles this exact problem for UI test automation.

This comprehensive guide will teach you how to leverage the power of Page Object Model and Page Factory in Selenium to write resilient, reusable and maintainable automated tests.

Challenges with UI Test Automation

Let‘s first understand why UI testing is complex:

  • Frequent UI changes – With agile development, the application UI evolves rapidly
  • Complex test code – UI tests often have convoluted code that interacts with many elements
  • Flaky tests – 30% of UI test failures are caused by flakiness making tests unreliable
  • Hard to maintain – With complex code and frequent UI changes, tests are difficult to maintain

These challenges slow down delivery cycles, waste precious testing time and affect software quality.

The Page Object Model approach provides solutions to these exact pain points.

What is the Page Object Model?

The Page Object Model (POM) is a design pattern that creates an abstraction layer between test code and application UI.

Here is how it works:

For each unique web page in the application, there is a corresponding Page Class. This class encapsulates the UI locators and methods interacting with page elements. Tests then use the methods exposed by Page Classes instead of directly accessing UI elements.

Page Object Model diagram

Image credit: Tom Hombergs on Medium

So why is this useful?

Benefits of the Page Object Model

Here are the major advantages of using the Page Object Model approach:

1. Improves test code maintainability

  • 60% reduction in script maintenance effort according to a Capability Assurance study
  • Changes required in fewer places since UI map separated from tests
  • Promotes reuse across multiple tests

2. Resilient to UI changes

  • Only Page Class needs to be updated on UI change
  • No updates required in test methods
  • 35% faster resolution of test failures due to UI changes

3. Forces modularity

  • Each Page Class has focused functionality
  • Logical grouping of user interactions
  • Promotes independent test creation

4. Facilitates collaboration

  • Separates test code from UI implementation
  • Enables parallel development between dev and QA teams
  • Promotes collective ownership

5. Optimizes execution

  • Operations can be performed faster since element locators initialized only once
  • Statelessness prevents stale element references
  • Conditional waits optimize performance

Overall, Page Object Model saves significant time, effort and leads to robust test automation.

Implementing Page Object Model with Selenium

Let‘s explore how to implement effective Page Objects with Selenium WebDriver using Java:

1. Identify unique pages

Analyze the application workflow and carve out logical pages. These should represent distinct UI layouts mapped to core user journeys.

For a banking app these could be:

  • Login Page
  • Accounts Summary Page
  • Funds Transfer Page
  • New Account Page

2. Create Page Class for each unique page

Here is how the Login Page class would look:

public class LoginPage {

    WebDriver driver; 

    //Locator for username input field
    @FindBy(id = "username") 
    WebElement username;

    //Locator for password input field 
    @FindBy(id = "password")
    WebElement password;

    //Locator for login button
    @FindBy(id = "login-button") 
    WebElement loginButton;

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

    //Method to login with username and password
    public void login(String un, String pw) {
        username.sendKeys(un);
        password.sendKeys(pw);
        loginButton.click();
    }
}

Here we initialize locators, encapsulate interactions and expose the login method.

3. Build reusable page methods

Page methods should be:

  • Task-focused – Perform cohesive action e.g. login(), addToCart()

  • Parameterized – Take inputs if needed to vary runtime data

  • Reusable – No test assertions, designed for cross-test use

4. Make tests use page methods

The test class creates Page objects and calls the encapsulated page methods:

public class LoginTests {

    WebDriver driver;
    LoginPage loginPage;

    @BeforeTest
    public void setup() {
        driver = new FirefoxDriver(); 
        loginPage = new LoginPage(driver);
    }

    @Test
    public void validLogin() {
        //Use login() method instead of complex UI code
        loginPage.login("john123", "pass456"); 
        Assert.assertTrue(driver.getCurrentURL().contains("/home"))
    }
}

This improves maintainability as tests focus on validation while Pages handle interactions.

Let‘s discuss some advanced Page Object Model implementations.

Types of Page Object Models

There are some extensions of the Page Object pattern that solve additional test automation challenges:

1. Layered Page Objects

Here page objects are grouped across layers for better abstraction based on what they represent – web elements, logical components like forms or mini workflows:

Layered Page Objects

Image credit: Angle Grinder Blog

2. PageFactory Pages

PageFactory introduces @FindBy annotations and initElements method to initialize locators avoiding redundancy.

3. Angular Page Objects

Specialized JavaScript based page objects for testing Angular applications.

So which variant makes most sense? It depends on application tech stack, team skills and scope of testing among other factors.

Page Object Model Best Practices

Here are some key best practices to implement page object pattern effectively:

  • Have only one instance of a page e.g. singleton pages
  • Idealize statelessness across page methods
  • Parameterize inputs variables for reusability
  • Nullify page instance references after usage
  • Implement lazy element initialization
  • Externalize environment data into config files
  • Follow naming conventions for uniformity

Page Object Model Tools and Frameworks

There are some popular open-source frameworks that facilitate easier page object implementations:

1. Selenium PageObject:

  • Native Ruby binding shipped with Selenium WebDriver
  • Includes PageFactory for annotating elements
  • Helper methods like on_page?()

2. FluentLenium:

  • Java fluent interface for concise Page Objects
  • Browser invocation and assertion features
  • Integrates with JUnit and TestNG

3. WebDriverIO:

  • JavaScript based bindings natively in Node.js
  • Supports synchronous and async test scripts
  • Active community, support for CI/CD

So in summary, Page Object Model is a versatile pattern that can be implemented across languages and test runners.

Page Object Model – Best Practices and Tips

Let‘s round up some key best practices to keep in mind:

Keep Pages lightweight

Pages should only contain element locators and interactions, not assertions or Conditional logic

Ideally make Pages stateless

Statelessness prevents stale element references and improves reusability

Parameterization aids reusability

Constructor and method inputs parameters promote reuse of Pages across tests

Nullify object references

Set page instance variables to null post usage to prevent memory leaks

Lazy load elements

Use annotations like @FindBy to lazy load locators only when referenced

Follow naming conventions

Use consistent locator naming schemes across the framework

Page Factory in Selenium

An extension of Page Object Model in Selenium is the Page Factory. This uses a special PageFacotry class to instantiate page objects in an optimized way.

Here is an example Page implemented using Page Factory:


@FindBy(id = "username") WebElement username;  

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

public LoginPage() {
   PageFactory.initElements(driver, this);  
}

public void login() {
  username.sendKeys("test");
  password.sendKeys("1234"); 
}

The key advantages Page Factory provides:

  • Removes need to use findElement explicitly
  • Annotates locators for readability
  • Lazy element initialization

So in summary, combine Page Factory with POM for optimal test automation framework.

Should You Adopt Page Object Model?

The Page Object Model brings invaluable benefits:

✔ 60% faster automation suite maintenance

✔ 35% quicker test failure diagnosis due to UI changes

✔ Enables 20% or more reusable test code

✔ 25% increased collaboration between dev and QA

So if you are dealing with:

  • Frequent regression test failures
  • High maintenance overhead
  • Lack of code reuse
  • Challenges in test data management

Page Object Model can drastically improve these aspects of UI test automation.

Conclusion

Here are the key highlights:

  • Page Object Model creates separation between test logic and UI
  • For each unique page have a Page Class encapsulating elements and interactions
  • Page methods should be reusable across tests
  • Tests should invoke Page methods instead of complex UI code
  • Page Factory provides annotation based elements for cleaner tests
  • Adoption leads to easier test maintenance with 60%+ savings in effort

So leverage the power of this pattern to boost productivity, reuse and reliability of your UI test automation initiatives.

Read More Topics