Editor’s note: This article was updated on 11/18/2022 by our editorial team. It has been modified to include recent sources and to align with our current editorial standards.
Automated tests are crucial for agile software development, enabling swift bug detection early in the development cycle. When a new feature is under development, developers can execute automated tests to observe its impact on other system components. This article will demonstrate how to expedite this process using test automation in Selenium with the Page Object model.
Test automation reduces bug fix costs and enhances the overall software quality assurance (QA) process. Thorough tests allow developers to identify and address bugs before they reach QA. Test automation further facilitates the automation of regression test cases and features. This frees QA engineers to focus on other application aspects, ensuring higher-quality production releases, leading to more stable products and a more efficient QA process.
While writing automated tests may appear straightforward for developers and engineers, poorly implemented tests and compromised code maintainability are potential pitfalls. The continuous delivery of changes or features in agile development can become expensive when tests are factored in. Modifying a webpage element on which 20 tests depend necessitates updating each of those 20 test routines, a time-consuming process that can discourage early automated testing.
But what if modifications could be made in a single location, automatically propagating to all relevant test routines? Let’s delve into automated tests in Selenium and explore how Page Object model best practices can create maintainable and reusable test routines.
Selenium Page Object Model
Page Object model is an object design pattern in Selenium that represents webpages as classes, with page elements defined as class variables. All potential user interactions can be implemented as methods within the class:
| |
Well-named methods in classes enhance readability, providing an elegant approach to implementing test routines that are both understandable and easy to maintain or update. For instance:
To support the Page Object model, we employ Page Factory. Page Factory in Selenium, an extension of the Page Object model, offers various usage options. We will utilize Page Factory to initialize web elements defined within webpage classes or Page Objects.
Before using web element variables, we need to initialize webpage classes or Page Objects containing them using Page Factory. This initialization is achieved using the initElements function of Page Factory:
| |
A simpler approach is:
| |
Or, within the webpage class constructor:
| |
Page Factory initializes each WebElement variable by referencing a corresponding element on the actual webpage based on configured “locators,” achieved using the @FindBy annotation. This annotation defines an element lookup strategy along with the necessary identification information:
| |
Whenever a method is called on this WebElement variable, the driver first locates it on the current page and then simulates the interaction. For simple pages where element presence is guaranteed and page revisits are unlikely, caching the located field using a simple annotation is possible:
| |
The entire WebElement variable definition can be condensed as follows:
| |
The @FindBy annotation supports various strategies for simplification, including id, name, className, css, tagName, linkText, partialLinkText, and xpath.
| |
Once initialized, these WebElement variables facilitate interaction with corresponding elements on the page. For instance, sending keystrokes to the password field:
| |
This is equivalent to:
| |
When identifying multiple elements on a page, the @FindBys annotation proves useful:
| |
This code snippet finds all div elements with both yt-lockup-tile and yt-lockup-video class names. This can be simplified further:
| |
Furthermore, @FindAll can be used with multiple @FindBy annotations to locate elements matching any given locator:
| |
Having established the representation of webpages as Java classes and the utilization of Page Factory for streamlined WebElement variable initialization, let’s proceed to write simple tests using the Page Object pattern and Page Factory in Selenium.
Simple Selenium Test Automation Project in Java
For our Selenium Page Object model tutorial, we’ll automate Toptal’s developer sign-up process, which involves the following:
Visiting www.toptal.com
Clicking the Apply As A Developer button
Verifying portal page opening
Clicking the Join Toptal button
Completing the form
Submitting the form by clicking the Join Toptal button
To execute this automation, we need to set up our Java project.
Setting Up a Project
After downloading and installing Java JDK and InteliJ Idea, we can proceed:
Creating a new Maven project
Linking
Project SDKto the JDK, e.g.,C:\Program Files\Java\jdkxxxon WindowsSetting up groupId (
<groupId>SeleniumTEST</groupId>) and artifactId (<artifactId>Test</artifactId>)Adding Selenium and JUnit Maven dependencies to the project POM file, ensuring
selenium.versionandjunit.versionare updated with the latest version numbers:
| |
If auto-build is enabled, dependency downloads should start automatically. Otherwise, activate Plugins > install > install:install under the Maven Projects panel in IntelliJ Idea.

With the project bootstrapped, we create our test package under src/test/java, naming it com.toptal. Under this package, two more are created: com.toptal.webpages and com.toptal.tests.

Page Object/Page Factory classes will reside under com.toptal.webpages, while test routines will be placed under com.toptal.tests.
We’ll have three Page Object classes:
Class | Description |
|---|---|
HomePage | Represents Toptal's homepage, www.toptal.com |
DeveloperPortalPage | Represents Toptal's developer portal page |
DeveloperApplyPage | Represents Toptal's developer application form |
Now, we can create the Page Object items.
Selenium Page Object Model: HomePage
The initial object represents Toptal’s homepage (www.toptal.com). We create a class named HomePage under com.toptal.webpages:
| |
Determining Element Locators
On Toptal’s homepage, our focus is on the Apply as a Developer button, which we can locate using its text. Finding and identifying elements while modeling webpages as Page Object classes can be tedious. Tools like Firefox Developer Tools or Chrome DevTools simplify this task. Right-clicking an element and selecting Inspect Element from the context menu reveals detailed element information.
By copying the element’s xpath, we create a WebElement field for it in our Page Object:
| |
Alternatively, using the tag name “h1” simplifies things if it uniquely identifies the target element:
| |
Selenium Page Object Model: DeveloperPortalPage
Next, we need a Page Object for the developer portal page accessed by clicking Apply As A Developer.
We’re interested in two elements on this page. To confirm page load, we’ll verify the heading’s existence. We also need a WebElement field for the Join Toptal button:
| |
Selenium Page Object Model: DeveloperApplyPage
Our third and final page object represents the page containing the developer application form. Due to multiple form fields, we define a WebElement variable for each, finding them by their id and defining specific setter methods to simulate keystrokes for each field:
| |
Writing a Simple Selenium Test
With Page Object classes representing pages and user interactions as their methods, we can now write our test routine as a series of straightforward method calls and assertions:
| |
Running the Test
Your project structure should now resemble this:

To run the test, right-click on ApplyAsDeveloperTest in the tree and select Run ‘ApplyAsDeveloperTest’.

Test results will be displayed in the lower left corner of your IDE:

Automation in Selenium for Maintainable Test Suites
Selenium’s Page Object and Page Factory simplify webpage modeling and automated testing, greatly benefiting both developers and QA engineers. When implemented effectively, these Page Object classes promote reusability throughout the test suite and enable early implementation of automated Selenium tests in projects without compromising agile development. By abstracting user interactions within page object models and maintaining concise test routines, your test suite can readily adapt to changing requirements with minimal effort.
I hope this effectively demonstrates how to write clean, maintainable test code. Always remember the golden rule of QA: “Think twice, code once!”