Selenium

Selenium Page Object Model Tutorial

Photo of Rajagopal ParthaSarathiRajagopal ParthaSarathiSeptember 6th, 2018Last Updated: April 8th, 2019
0 318 6 minutes read

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.
 
 

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.

Selenium Page Object Model - Login Page
Login Page

Index.html will just display the logged in user via thesessionstorage.sessionstorage resides until the user closes the browser window.

Selenium Page Object Model - Index Page
Index Page

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 declareassert4j,Selenium andjunit as 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 thegeckodriver andchromedriver for firefox and chrome respectively.
  • Driver download Path is mentioned in lines 1-2 ofapplication.properties.
  • We provide browser aschrome for testing our application.
  • Path to the webpage is provided inlogin.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:

Want to master Selenium?
Subscribe to our newsletter and download theSeleniumProgramming Cookbookright now!
In order to get you prepared for your Selenium development needs, we have compiled numerous recipes to help you kick-start your projects. Besides reading them online you may download the eBook in PDF format!

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 adomElement using itsid for the three fields –username,password andlogin 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 itsid. Here it is a span element but there is no distinction on the locator.
  • We assert the value ofSpan is 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

Download
You can download the full source code of this example here:Page Object Model
Do you want to know how to develop your skillset to become aJava Rockstar?
Subscribe to our newsletter to start Rockingright now!
To get you started we give you our best selling eBooks forFREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to theTerms andPrivacy Policy

Thank you!

We will contact you soon.

Photo of Rajagopal ParthaSarathiRajagopal ParthaSarathiSeptember 6th, 2018Last Updated: April 8th, 2019
0 318 6 minutes read
Photo of Rajagopal ParthaSarathi

Rajagopal ParthaSarathi

Rajagopal works in software industry solving enterprise-scale problems for customers across geographies specializing in distributed platforms. He holds a masters in computer science with focus on cloud computing from Illinois Institute of Technology. His current interests include data science and distributed computing.
Subscribe
Notify of
guest
I agree to theTerms andPrivacy Policy
The comment form collects your name, email and content to allow us keep track of the comments placed on the website. Please read and accept our website Terms and Privacy Policy to post a comment.

I agree to theTerms andPrivacy Policy
The comment form collects your name, email and content to allow us keep track of the comments placed on the website. Please read and accept our website Terms and Privacy Policy to post a comment.