Design patterns are the best solutions and practices to the software architecture which is evolved over time by many industry experts while working with different design problems. They are templates or designs to standardize the software architecture. Page Object Model (POM) and Page Factory are the two commonly used design patterns in Selenium.
Page Object Model (POM)
Page Object Model is one of the most popular design patterns and can be implemented in Selenium WebDriver. POM considers each web page of an application as an object. To get a better understanding of this concept, let us take a look into how an automation test works:
Automation test allows us to navigate to different web pages and perform relevant actions with the web elements. These web elements are identified using different locators like id, xpath, class name etc. In Page Object Model, a separate java class is created under separate package for web elements, each class file contains all the web elements and their action methods.
POM is an efficient design pattern to systematically organize the scripts in such a way that makes it easier for QA engineers to maintain the code hassle free and prevent code redundancy. For example, if there is a change in the locator value of a specific element which has been accessed by more than one test script, then it is very easy to identify and change the locator value without impacting the code elsewhere.
Example for Non-Page Object Model
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.edge.EdgeDriver;
import org.testng.Assert;
import org.testng.annotations.Test;
public class LoginWithNoPOM {
@Test
public void login() {
//setup
WebDriver edgedriver = new EdgeDriver();
edgedriver.get("https://www.saucedemo.com/");
edgedriver.manage().window().maximize();
//login
WebElement usernameTxtBox = edgedriver.findElement(By.id("user-name"));
usernameTxtBox.sendKeys("standard_user");
WebElement passwordTxtBox = edgedriver.findElement(By.id("password"));
passwordTxtBox.sendKeys("secret_sauce");
WebElement submitBtn = edgedriver.findElement(By.id("login-button"));
submitBtn.click();
WebElement homePageTitle = edgedriver.findElement(By.xpath("//div/span[@class=\"title\"]"));
System.out.println(homePageTitle.getText());
Assert.assertEquals(homePageTitle.getText(),"PRODUCTS");
edgedriver.close();
}
}
Example for Page Object Model
POM page class
package pom_pages;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class LoginWithPOM_PageClass {
By usernameTxtBox = By.id("user-name");
By passwordTxtBox = By.id("password");
By submitBtn = By.id("login-button");
By homePageTitle = By.xpath("//div/span[@class=\"title\"]");
WebDriver edgedriver;
public LoginWithPOM_PageClass(WebDriver driver) {
this.edgedriver = driver;
}
public void username(String strUserName) {
edgedriver.findElement(usernameTxtBox).sendKeys(strUserName);
}
public void password(String strPassword) {
edgedriver.findElement(passwordTxtBox).sendKeys(strPassword);
}
public void loginBtn() {
edgedriver.findElement(submitBtn).click();
}
public String getHomePageTitle() {
return edgedriver.findElement(homePageTitle).getText();
}
}
POM test case class
package pom_testcases;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.edge.EdgeDriver;
import org.testng.Assert;
import org.testng.annotations.Test;
import pom_pages.LoginWithPOM_PageClass;
public class LoginWithPOM_Testcase {
static WebDriver edgedriver;
static LoginWithPOM_PageClass objPOM;
@Test
public void login() {
//setup
edgedriver = new EdgeDriver();
edgedriver.get("https://www.saucedemo.com/");
edgedriver.manage().window().maximize();
LoginWithPOM_PageClass objPOM = new LoginWithPOM_PageClass(edgedriver);
//login
objPOM.username("standard_user");
objPOM.password("secret_sauce");
objPOM.loginBtn();
Assert.assertEquals(objPOM.getHomePageTitle(),"PRODUCTS");
edgedriver.close();
}
}
Folder Structure
Page Factory
Page factory is an optimized version of Page Object Model in Selenium WebDriver. In Page Factory, web elements are declared as variables. To support Page Object Model design pattern, Selenium libraries contain the Page Factory class that makes the usage of Page Objects simpler and easier. When using Page Factory, annotations like @FindBy, @FindBys, @FindAll etc. are used for locating web elements.
The major benefit of using these annotations is that it lazy initialize the page elements without using driver.FindElement(or FindElements). The Page Factory class also provides the ‘initElements’ method for reinitializing the web elements.
Example for Page Factory class
Page Factory page class
package pom_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 LoginWithPageFactory {
WebDriver edgedriver;
public LoginWithPageFactory(WebDriver driver){
edgedriver = driver;
PageFactory.initElements(edgedriver, this);
}
@FindBy(id = "user-name") WebElement usernameTxtBox;
@FindBy(id = "password") WebElement passwordTxtBox;
@FindBy(id = "login-button") WebElement submitBtn;
@FindBy(xpath = "//div/span[@class=\"title\"]") WebElement homePageTitle;
public void username(String strUserName) {
usernameTxtBox.sendKeys(strUserName);
}
public void password(String strPassword) {
passwordTxtBox.sendKeys(strPassword);
}
public void loginBtn() {
submitBtn.click();
}
public String getHomePageTitle() {
return (homePageTitle.getText());
}
}
Page Factory test case class
package pom_testcases;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.edge.EdgeDriver;
import org.testng.Assert;
import org.testng.annotations.Test;
import pom_pages.LoginWithPageFactory;
public class LoginWithPageFactory_Testcases {
static WebDriver edgedriver;
static LoginWithPageFactory objPF;
@Test
public void login() {
//setup
edgedriver=new EdgeDriver();
edgedriver.get("https://www.saucedemo.com");
edgedriver.manage().window().maximize();
LoginWithPageFactory objPF = new LoginWithPageFactory(edgedriver);
//login
objPF.username("standard_user");
objPF.password("secret_sauce");
objPF.loginBtn();
Assert.assertEquals(objPF.getHomePageTitle(), "PRODUCTS");
edgedriver.close();
}
}
A Comparison of Page Object Model and Page Factory
1.Page Objective Model is an approach for design patterns while Page Factory is a class provided by Selenium WebDriver to implement POM.
2. In POM, ‘By’ is used to find web elements while in Page Factory ‘@FindBy’ annotation is used.
3. POM does not provide lazy initialization while Page Factory does provide lazy initialization.
4. Page Factory is an optimal method than POM.
5. POM requires the initialization of every object while in Page Factory, all page objects are initialized by using the initElements() method.
Conclusion
Design patterns, Page Object Model and Page factory, provide a clear separation between web elements and test cases which in turn have many advantages like code reusability, better readability, reliability, easy code maintenance, and well-organized clean code.
Happy Learning!!