Chapter[20]: Essential Design Patterns for Automating a Whole Website

Automate This. By Mrigank Saxena
3 min readFeb 11, 2025

--

Image by freepik

Why Do We Need Design Patterns in Automation?

Let’s say you’re building a car. You wouldn’t randomly weld metal pieces together, right? You’d follow a structured plan so that everything fits perfectly and functions smoothly.

Automation is the same! Without structure, your test scripts become a chaotic mess — hard to maintain, impossible to scale.

This is where design patterns come in. They help organize code so that it is reusable, maintainable, and scalable.

Let’s explore some must-know design patterns for automation.

1. Singleton Pattern — Managing a Single WebDriver Instance

Problem:

If every test case creates a new WebDriver instance, multiple browsers will open, which slows down execution and consumes unnecessary resources.

Solution:

The Singleton Pattern ensures that only one WebDriver instance is used throughout the test execution.

How It Works:

  • Prevents multiple browsers from opening unnecessarily.
  • Ensures the same WebDriver instance is used across tests.

Code Example:

public class WebDriverManager {

private static WebDriver driver; // Single WebDriver instance


// Private constructor to prevent external object creation
private WebDriverManager() {}

// Method to return the single WebDriver instance
public static WebDriver getInstance() {
if (driver == null) { // If no driver instance exists, create one
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
}

return driver; // Return the same instance every time
}
}

How to Use It in Your Tests?

WebDriver driver = WebDriverManager.getInstance();

With this approach, only one browser window is opened and shared across test cases.

2. Page Object Model (POM) — Organizing Your Code

Problem:

Locators (By.xpath(), By.id()) are scattered throughout test scripts, making updates a nightmare when something changes on the website.

Solution:

The Page Object Model (POM) separates UI elements into dedicated classes, keeping the test scripts clean and readable.

Code Example:

public class LoginPage {
private WebDriver driver; // WebDriver instance for this page


// Define locators for elements
By usernameField = By.id("username");
By passwordField = By.id("password");
By loginButton = By.id("login");

// Constructor to initialize WebDriver
public LoginPage(WebDriver driver) {
this.driver = driver;
}

// Method to enter username
public void enterUsername(String username) {
driver.findElement(usernameField).sendKeys(username);
}

// Method to enter password
public void enterPassword(String password) {
driver.findElement(passwordField).sendKeys(password);
}

// Method to click the login button
public void clickLogin() {
driver.findElement(loginButton).click();
}
}

How to Use It in Your Test?

LoginPage login = new LoginPage(driver);
login.enterUsername("user123");
login.enterPassword("password123");
login.clickLogin();

If the login button’s ID changes in the future, you only update it in the LoginPage class, instead of searching through multiple test cases.

3. Factory Pattern — Creating WebDriver Instances Dynamically

Problem:

You want to run tests on multiple browsers like Chrome, Firefox, and Edge, but hardcoding each one isn’t practical.

Solution:

The Factory Pattern lets you create WebDriver instances dynamically based on input(Note: This is just a basic example, we will learn more about this in the upcoming articles).

Code Example:

public class chooseBrowserType{

// Method to create a WebDriver instance based on browser type
public static WebDriver getDriver(String browserType) {
switch (browserType.toLowerCase()) {
case "chrome":
WebDriverManager.chromedriver().setup();
return new ChromeDriver(); // Returns ChromeDriver instance
case "firefox":
WebDriverManager.firefoxdriver().setup();
return new FirefoxDriver(); // Returns FirefoxDriver instance
default:
throw new IllegalArgumentException("Browser not supported: " + browserType);
}
}
}

How to Use It in Your Test?

WebDriver driver = DriverFactory.getDriver("chrome");

Now, changing the browser is super easy!

4. Fluent Interface Pattern — Cleaner Test Steps

Problem:

Test scripts can get cluttered and hard to read.

Solution:

The Fluent Interface Pattern allows method chaining, making test steps more readable.

Code Example:

public class LoginPage {
private WebDriver driver;

public LoginPage(WebDriver driver) {
this.driver = driver;
}

// Method to enter username with method chaining
public LoginPage enterUsername(String username) {
driver.findElement(By.id("username")).sendKeys(username);
return this; // Returns the same object for chaining
}

// Method to enter password with method chaining
public LoginPage enterPassword(String password) {
driver.findElement(By.id("password")).sendKeys(password);
return this;
}

// Method to click login button with method chaining
public LoginPage clickLogin() {
driver.findElement(By.id("login")).click();
return this;
}
}

How to Use It in Your Test?

new LoginPage(driver)
.enterUsername("user123")
.enterPassword("password123")
.clickLogin();

This makes test scripts easier to read and maintain.

.

.

.

Happy Coding!

--

--

Automate This. By Mrigank Saxena
Automate This. By Mrigank Saxena

Written by Automate This. By Mrigank Saxena

Join me as I share insights, tips, and experiences from my journey in quality assurance, automation, and coding! https://www.linkedin.com/in/iammriganksaxena/

No responses yet