Selenium Page Object Model Tutorial
This article is an introduction to the Selenium Page Object Model and how we can leverage it for better readability and code reuse.
1. Selenium Page Object Model – Introduction
Selenium is used to automate browsers. Selenium WebDriver has found its place in test automation for web applications. It is used to create robust, browser-based regression automation suites and tests. Inherent to this flexibility, there lies a bit of complexity. Testing for large applications might result in lot of code repetition from selenium end. Page Objects promotes code re-usability and simpler structures for clarity.
Table Of Contents
We will cover first the automation of a simple page with vanillaSelenium. We will introduce then the Page Object Model to see the benefits it brings to the table. We will extend it further withPageFactory class which provides even more simpler code.
2. Technologies Used
- IntelliJ Idea (Any Java IDE would work)
- Java 1.8.101 (1.8.x will do fine)
- GeckoDriver (firefox)
- ChromeDriver (Chrome)
- Maven
- Selenium
- junit
- assert4j
3. Resources
To illustrate the Selenium’s capability, we will create two web pageslogin.html andindex.html.login.html will contain a username and password textbox along with Login button to submit the page.
Index.html will just display the logged in user via thesessionstorage.sessionstorage resides until the user closes the browser window.
Our objective is to automate the testing of these two pages viaSelenium. To automate this, we create aMaven project with the followingpom.xml
pom.xml
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.jcg</groupId> <artifactId>pageObjectModel</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> <version>3.10.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>3.13.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.6.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build></project>
- We declare
assert4j,Seleniumandjunitas dependencies - We define Maven compiler to assemble the jar output and configure it with Java version of 1.8
Assert4J provides a fluent assertion library for our testing purposes.Selenium is used to control thewebdriver and is the scope of our discussion.Junit is used to fire our test cases. We are coveringSelenium here from the testing point of view.
Next, We will coverapplication.properties. This is used to control the properties of the application which are loaded on Startup ofDriverInitializer class. This controls the behavior of our application.
application.properties
chrome.path=/usr/local/bin/chromedrivergecko.path=/usr/local/bin/geckodriverbrowser=chromelogin.url=file:///JCG/pageObjectModel/src/main/resources/login.html
- We need to download the
geckodriverandchromedriverfor firefox and chrome respectively. - Driver download Path is mentioned in lines 1-2 of
application.properties. - We provide browser as
chromefor testing our application. - Path to the webpage is provided in
login.url.
DriverInitializer class is used to load the default properties for our application. It is used to get the necessary driver used for testing of our application.
DriverInitializer.java
package com.jcg.PageObjectModel;import org.openqa.selenium.WebDriver;import org.openqa.selenium.chrome.ChromeDriver;import org.openqa.selenium.firefox.FirefoxDriver;import java.util.Properties;public class DriverInitializer { private static Properties properties = null; private static WebDriver driver = null; static { try { properties = new Properties(); properties.load(DriverInitializer.class.getClassLoader() .getResourceAsStream("application.properties")); System.setProperty("webdriver.chrome.driver", properties.getProperty("chrome.path")); System.setProperty("webdriver.gecko.driver", properties.getProperty("gecko.path")); switch (getProperty("browser")) { case "chrome": driver = new ChromeDriver(); break; case "firefox": driver = new FirefoxDriver(); break; default: driver = new ChromeDriver(); } } catch (Exception e) { e.printStackTrace(); } } public static WebDriver getDriver() { return driver; } public static String getProperty(String key) { return properties == null ? null : properties.getProperty(key, ""); }}The properties are read from theapplication.properties available in the classpath. Based on the properties,firefoxdriver andchromedriver paths are set. Based on the browser configured in property, either firefox or chrome is used. This class exposes two methods:
getDriver– Provides the appropriate driver based on the browser configured in the property file.getProperty– Provides a convenient method to access the property value based on the provided key.
4. Vanilla Selenium
Let’s start with the plain vanilla approach of accessing the page and automating the input. Before that, We will see the needed methods for all our test cases to work.
TestLogin.java
package com.jcg.pageObjectModel.test;import com.jcg.PageObjectModel.DriverInitializer;import com.jcg.PageObjectModel.IndexPage;import com.jcg.PageObjectModel.LoginPage;import org.junit.AfterClass;import org.junit.Before;import org.junit.BeforeClass;import org.junit.Test;import org.openqa.selenium.By;import org.openqa.selenium.WebDriver;import org.openqa.selenium.WebElement;import static org.assertj.core.api.Assertions.*;public class TestLogin { static WebDriver webDriver; @BeforeClass public static void setUp() throws Exception { webDriver = DriverInitializer.getDriver(); } @AfterClass public static void tearDown() { webDriver.quit(); } @Before public void navigate() { webDriver.get(DriverInitializer.getProperty("login.url")); }}We get the necessary web driver usingDriverIntiliazer class insetUp which runs at the start of our test class. It has to be a static method as it is run at the class level. Before the execution of each test case, We open up the login page URL in thenavigate method. Here it is conveniently used with@Before annotation. Ideally, each test case might open a different URL and would not be always in this manner.
After the entire test suite is completed, We use thetearDown method to close the browser and exit the selenium session. This is to ensure that the browser does not remain open and consume resources.
We will look at the actual test case to test our functionality.
TestCase1:

Thank you!
We will contact you soon.
@Test public void login() { WebElement webElement = webDriver.findElement(By.id("username")); webElement.sendKeys("hi"); webElement = webDriver.findElement(By.id("password")); webElement.sendKeys("hi"); webElement = webDriver.findElement(By.id("login-btn")); webElement.click(); webElement = webDriver.findElement(By.id("name")); assertThat(webElement.getText()).isEqualTo("hi"); }- We find a
domElementusing itsidfor the three fields –username,passwordandlogin button. - We send the value hi to username and password field.
- Subsequently, we click on the login button.
- Page navigation happens and we look up the name field by its
id. Here it is a span element but there is no distinction on the locator. - We assert the value of
Spanis the username we provided in the login page.
5. Page Object Model
In the previous example, we were able to automate our testing. But if thislocator had to be reused again, it needs to be redefined again. There will be a lot of repetitive code involved in each test case. This lead to the concept of Page Object Model. At a high level, all elements on a page should be moved as locators in a single class. For complex applications, Page model does not equate to a single page but covers a single repeated functionality. We will transform the previous test case to the page model in iterations.
LoginPage.java
public class LoginPage { public static By usernameLocator = By.id("username"); public static By passwordLocator = By.id("password"); public static By loginButtonLocator = By.id("login-btn");}As the first step, We moved the locators to a classLoginPage which will serve as the page model. Now we can convert the previous example into the below manner.
driver.findElement(LoginPage.usernameLocator).sendKeys(username);driver.findElement(LoginPage.passwordLocator).sendKeys(password);driver.findElement(LoginPage.loginButtonLocator).click();
This seems better than the previous approach but it is not complete. We are going to reuse the entire login functionality and not just the username locator etc. So it might be better to have the complete login function for reuse. At the same time,Index has only one simple locator which can be directly used from Index page Object.
IndexPage.java
public class IndexPage { public static By usernameLocator = By.id("name");}This just contains the span locator to verify the username is passed onto the index page.
LoginPage.java(With Login)
public class LoginPage { public static By usernameLocator = By.id("username"); public static By passwordLocator = By.id("password"); public static By loginButtonLocator = By.id("login-btn"); public static void logInWithUsernameAndPassword (String username, String password, WebDriver driver) { driver.findElement(usernameLocator).sendKeys(username); driver.findElement(passwordLocator).sendKeys(password); driver.findElement(loginButtonLocator).click(); }}This is an extension to the previous implementation. Here, thelogInWithUsernameAndPassword is used to abstract the login functionality as a single unit to the external world. It just needs thewebDriver to execute the test case.
TestCase 2:
@Test public void loginPageModel() { LoginPage.logInWithUsernameAndPassword("hi", "hi", webDriver); assertThat(webDriver.findElement(IndexPage.usernameLocator).getText()).isEqualTo("hi"); }Now the test case is much simpler. LoginPage’s login method is used to execute login functionality on the page while IndexPage’s name locator is used to verify the name. This approach provides excellent reuse and less coupled code.
6. Page Factory
The previous approach provided a simpler and reusable version of the test case. Selenium provides thePageFactory class to further streamline our test case.
LoginPage.java(Page Factory)
public LoginPage(WebDriver driver) { PageFactory.initElements(driver, this);}@FindBy(how = How.ID, using = "username")private WebElement userName;@FindBy(how = How.ID, using = "password")private WebElement password;@FindBy(how = How.ID, using = "login-btn")private WebElement login;public void logIn(String userName, String password) { this.userName.sendKeys(userName); this.password.sendKeys(password); this.login.click();}We initialize thePageFactory class withWebDriver and pass our instance to thePageFactory. This enables thePageFactory class to pass the webdriver to our annotated instance variables. We have three locators via the instance variables username,password and login. UsingFindBy annotation, we specify that we lookup an element by its ID and the corresponding id is username for the username element. Based on this declaration, we get a simplified element locator at class level.
The logIn implementation uses these locators to carry out the expected functionality.
TestCase3
@Test public void loginPageFactory() { new LoginPage(webDriver).logIn("hi", "hi"); assertThat(webDriver.findElement(IndexPage.usernameLocator).getText()).isEqualTo("hi"); }In this test case, We just provide the appropriate driver to thepageModel class during initialization itself. Once the class is initialized, We call thelogIn method to execute the login activity. Assertion is similar to the previous test case.
7. Summary
In this tutorial, we saw how the concept ofPage Model brings clarity over the plainSelenium driven way. We extended it further withPageFactory which had nice java annotation goodies.
8. Download the Source Code
You can download the full source code of this example here:Page Object Model

Thank you!
We will contact you soon.





