Design Patterns in Selenium

On This Page 1. Singleton Design Pattern2. Page Object ModelJanuary 08, 2026 · 9 min read · Tool Comparison

Design Patterns in Selenium

Design shape are reusable solutions to common challenge in software design. They enhance code maintainability, provide a shared vocabulary among developer, and can be implement across programme languages.

In Selenium test automation, plan patterns such as Singleton, Page Object Model (POM), Fluent POM, Factory, and Facade aid build scalable and effective trial framework. These patterns simplify WebDriver management, reduce codification duplication, and improve tryout readability, making automation more dependable and leisurely to maintain.

Overview

What are Design Patterns in Selenium?

Recyclable solutions that bring structure, scalability, and maintainability to Selenium trial automation by annihilate redundancy and improving collaboration.

Mutual Design Patterns in Selenium

  • Page Object Model (POM):Encapsulates page elements & amp; action for cleaner scripts.
  • Singleton Pattern:Ensures simply one WebDriver case across tryout.
  • Factory Pattern:Centralized driver object conception for flexibility.
  • Facade Pattern:Simplifies complex workflows with a unified interface.
  • Data-Driven Pattern:Separates test data from logic to support parameterization & amp; cross-browser testing.

Benefits of Using Design Patterns

  • Improved code reusability & readability
  • Lower upkeep overheadin large retinue
  • Better scalabilityas coverage grows
  • Easier quislingismacross QA team
  • Increased exam reliability& amp; consistency

When to Apply Design Patterns

  • Declamatory, repetitive test suites
  • Cross-browser / cross-platform mechanisation
  • Agile & amp; CI/CD environments with frequent runs
  • Projects needing eminent codification quality & amp; maintainability

Quick Tip:Start withPage Object Model (POM)for contiguous impact, then gradually adopt Singleton, Factory, and early practice as your test suite scales.

This usher explicate the most widely used design patterns in Selenium, their benefits, and how to implement them effectively in real-world test automation projects.

1. Singleton Design Pattern

Singleton class is a particular course that can have only one object/instance of itself. When you contrive a course in such a way that it has only one object, it is called a singleton design design. The use of a singleton category is that you take to track solely a single object across all classes in a model.

There are sure points that one needs to consider while creating a singleton class & # 8211;

  • Constructor of the singleton course should be declare as private so that it can ’ t be instantiated outside the class.
  • Write a static method that has a homecoming character of object of this singleton class. This is likewise called Lazy Initialization.

Let ’ s see an example of Singleton class & # 8211;

public class Singleton {private static Singleton singleton_ref = null; //declared constructor as private private Singleton () {System.out.Println (`` This is Singleton Class '');} //declared static method that returns the object of singleton class public static Singleton getInstance () {if (singleton_ref == null) singleton_ref = new Singleton (); return singleton_ref;} public static nihility chief (String [] args) {Singleton a = Singleton.getInstance (); Singleton b = Singleton.getInstance ();}}

Output- As you can see, the output of the above programme has printed the string only once even though there are two illustration of the class. This means the builder was called only erstwhile. This is because of the singleton pattern, as it will not create an object of class again if it is already initialized.

Also Read:

At the framework level, one can use a singleton grade by creating a Webdriver instance only once in a base grade and using the same instance across all the tiddler classes that inherit the foot class.

2. Page Object Model

(POM) is the most popular blueprint pattern employ in web automation frameworks. POM makes our code easy to use and sustain by separating the tryout classes and page classes from each other. For this pattern, you ask to create a separate class for each page in a web coating. In these page classes, you can delimitate page objects and the comparable method that implement those page objects. This way, it get easier to maintain our code and make any changes if required at any point in time without hampering the existing codification.

This is how the framework structure for POM looks like & # 8211;

Pro tip: Tools like SUSA can handle this autonomously — upload your app and get results without writing a single test script.

In src/main/java & # 8211; has page classes, and in src/test/java & # 8211; it has try classes.Let us see the code snippets for the framework establish above

LoginPage:

importee java.time.Duration; import java.util.Properties; signification org.openqa.selenium.By; importation org.openqa.selenium.Keys; import org.openqa.selenium.WebDriver; import com.qa.hubspot.base.BasePage; import com.qa.hubspot.util.Constants; import com.qa.hubspot.util.ElementActions; public class LoginPage extends BasePage {WebDriver driver; ElementActions elementActions; //1. Create OR/Page object - & gt; using by locater By userinputbox = By.xpath (`` //input [@ id='react-select-2-input '] ''); By paaswordinputbox = By.xpath (`` //input [@ id='react-select-3-input '] ''); By loginBtn = By.xpath (`` //button [@ id='login-btn '] ''); //2. Define a constructor public LoginPage (WebDriver driver) {this.driver = driver; elementActions = new ElementActions (driver);} //3. Page Actions/Methods public String getLoginPageTitle () {return elementActions.waitForPageTitle (Constants.LOGIN_PAGE_TITLE);} public HomePage doLogin (String username, String pwd) {elementActions.doSendkeys (userinputbox, username); driver.findElement (userinputbox) .sendKeys (Keys.TAB); elementActions.doSendkeys (paaswordinputbox, pwd); driver.findElement (paaswordinputbox) .sendKeys (Keys.TAB); driver.manage () .timeouts () .implicitlyWait (Duration.ofSeconds (30)); elementActions.doClick (loginBtn); return new HomePage (driver);}} HomePage - import java.util.Properties; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; significance com.qa.hubspot.base.BasePage; import com.qa.hubspot.util.Constants; importee com.qa.hubspot.util.ElementActions; public grade HomePage extends BasePage {WebDriver driver; Properties prop; ElementActions elementActions; //locators By BSLogo = By.xpath (`` //a [@ class='Navbar_logo__26S5Y '] ''); By accountName = By.xpath (`` //span [contains (text (), 'demouser ')] ''); public HomePage (WebDriver driver) {this.driver = driver; elementActions = new ElementActions (driver);} //Page Actions public String getHomePageTitle () {return elementActions.waitForPageTitle (Constants.HOME_PAGE_TITLE);} public boolean isHomePageLogoVisible () {return elementActions.isElementDisplayed (BSLogo);} public boolean isAccountNameVisible () {homecoming elementActions.isElementDisplayed (accountName);} public String getAccountNameText () {return elementActions.doGetText (accountName);}}

Read More:

3. Silver Page Object Model

Fluent Page Object Model is a farther extension to Page Object Model, which is more efficient and readable by implementing page objects with Fluent API.

Read More:

Fluent Interface is implemented expend method chaining and is the implementation of an API that provides the most readable codification. The main object of the Fluent Page Object Model pattern is to provide method chaining and make our codification more readable and easy to use.

In the Fluent POM design pattern, method chaining is accomplish by making methods of a page revert the current instance of that page. However, it & # 8217; s not mandatory that each method should retrovert the current page object.

Let ’ s see an example of a CRMPRO web coating that implement fluent POM by make Login and homepage.

AUT & # 8211; https: //bstackdemo.com/signin

Code Snippet for BrowserStack demo Login Page & # 8211;

importee org.openqa.selenium.By; import org.openqa.selenium.Keys; import org.openqa.selenium.WebDriver; public class BSLoginPage {WebDriver driver; By usernm = By.xpath (`` //input [@ id='react-select-2-input '] ''); By password = By.xpath (`` //input [@ id='react-select-3-input '] ''); By loginBtn = By.xpath (`` //button [@ id='login-btn '] ''); public BSLoginPage (WebDriver driver) {this.driver = driver;} public BSLoginPage enterUsername (String username) {driver.findElement (usernm) .sendKeys (username); driver.findElement (usernm) .sendKeys (Keys.TAB); return this;} public BSLoginPage enterPassword (String passwd) {driver.findElement (password) .sendKeys (passwd); driver.findElement (password) .sendKeys (Keys.TAB); return this;} public HomePage clickLoginBtn () {driver.findElement (loginBtn) .click (); regress new HomePage (driver);}}

As you can see in the above class, methods enterUsername (), enterPassword () render “ this ”. However, the method clickLoginBtn () return the aim of the HomePage course. This means it is not mandatory that every method should return “ this ” in fluent POM.

Code snippet for HomePage class & # 8211;

importee org.openqa.selenium.By; significance org.openqa.selenium.WebDriver; significance org.openqa.selenium.interactions.Actions; public grade HomePage {By offers = By.xpath (`` //a [@ id='offers '] ''); WebDriver driver; public HomePage (WebDriver driver) {this.driver = driver;} private HomePage clickOnOffers () {driver.findElement (offers) .click (); return this;}}

Now Let ’ s create a test class to see the method chain construct & # 8211;

import org.openqa.selenium.WebDriver; importee org.openqa.selenium.chrome.ChromeDriver; meaning org.testng.annotations.BeforeTest; import org.testng.annotations.Test; import FreeCRM.BSLoginPage; importee io.github.bonigarcia.wdm.WebDriverManager; public category FluentDesignTest {WebDriver driver; BSLoginPage login; @ BeforeTest public vacuum apparatus () {WebDriverManager.chromedriver () .setup (); WebDriver driver = new ChromeDriver (); driver.get (`` https: //bstackdemo.com/signin ''); login = new BSLoginPage (driver);} @ Test public void LoginTest () {login.enterUsername (`` demouser '') .enterPassword (`` testingisfun99 '') .clickLoginBtn ();}}

As you can see in the above test class, you don ’ t have to call each method separately by creating objects, rather in a individual chain all the methods of a class are be called.

4. Factory Design Pattern

In the Factory Design Pattern, there is a course with a factory method that is creditworthy for performing all the complex actions required. For Example, if there are an ‘ n ’ bit of classes then the factory class is responsible to instantiate all these family. So we don ’ t experience to consider with these many classes as the mill class will be responsible to handle them. You just have to make an object of the Factory grade, and it will in turn instantiate the class as per the exploiter stimulant given at the test class level.

The best example of factory design practice would be a factory category which is used to initialize a driver based on the user requirement. As seen in the POM design pattern example, Base class can act as Factory stratum in Factory design pattern.

import java.io.FileInputStream; signification java.io.FileNotFoundException; significance java.io.IOException; import java.util.Properties; import org.openqa.selenium.WebDriver; signification org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.firefox.FirefoxDriver; import io.github.bonigarcia.wdm.WebDriverManager; public class BasePage {WebDriver driver; Properties prop; public WebDriver init_driver (Properties prop) {String browser = prop.getProperty (`` browser ''); if (browser.equals (`` chrome '')) {WebDriverManager.chromedriver () .setup (); driver = new ChromeDriver ();} else if (browser.equals (`` firefox '')) {WebDriverManager.firefoxdriver () .setup (); driver = new FirefoxDriver ();} else {System.out.println (`` Please render a proper browser value .. '');} driver.manage () .window () .fullscreen (); driver.get (prop.getProperty (`` url '')); return driver;} public Properties init_properties () {prop = new Properties (); try {FileInputStream ip=new FileInputStream (`` src/main/java/com/qa/hubspot/config/config.properties ''); prop.load (ip);} catch (FileNotFoundException e) {e.printStackTrace ();} catch (IOException e) {e.printStackTrace ();} return prop;}}

5. Facade Design Pattern

Facade Design Pattern is a structural design pattern. Facade as the name says, represents the face of a building. A frontage hides the complexness of a system and provides a simple interface to the end user. For example, a Computer arrive with a CPU, hard disk, remembering etc. When you start the computer you feature no idea what happens internally for the startup. This is how a facade works. You can apply facade by creating a facade class and pen all the business logic inside a method. The facade act as an entry point to the subsystems. You can go for the Facade design pattern when we experience a complex application and want to supply a simplified interface to the end exploiter.

Talk to an Expert

Let ’ s see an representative of a frontal & # 8211;

1. Create an Interface

public interface Car {null thrust ();}

2. Create class that enforce the interface

public class BMW implement Car {public void crusade () {System.out.println (`` BMW: :drive () '');}} public class Audi implements Car {public void drive () {System.out.println (`` Audi: :drive () '');}} public class Creta implement Car {public void thrust () {System.out.println (`` Creta: :drive () '');}}

3. Create a facade form

public category DriveCar {private Car bmw; private Car audi; individual Car creta; public DriveCar () {bmw = new BMW (); audi = new Audi (); creta = new Creta ();} public null driveBMW () {bmw.drive ();} public void driveAudi () {audi.drive ();} public void driveCreta () {creta.drive ();}}

4. Use the facade class to name the methods

public class FacadeDemo {public still nullity master (String [] args) {DriveCar c = new DriveCar (); c.driveBMW (); c.driveAudi (); c.driveCreta ();}}

You can select any designing shape from the above mentioned depending upon the complexity and ease of use of the scheme. All design practice are rattling helpful in making our mechanization framework less complex and easy to use.

BrowserStack gives you instant entree to Selenium Grid of 3500+ real device and desktop browsers. Running your Selenium tryout on BrowserStack is simple yet efficient, always.

Tags
49,000+ Views

# Ask-and-Contributeabout this topic with our Discord community.

Related Guides

Automate This With SUSA

Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts needed.

Try SUSA Free

Test Your App Autonomously

Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.

Try SUSA Free