Wednesday, July 30, 2025

🔐 How I Used OOPS Concepts in My Selenium Automation Framework (with Real-World Examples)


In today’s test automation world, building scalable, maintainable, and readable frameworks is non-negotiable. One of the key enablers of such robust automation design is the effective use of Object-Oriented Programming (OOPS) principles.

In this post, I’ll walk you through how I have practically applied OOPS concepts like Encapsulation, Inheritance, Abstraction, and Polymorphism in building a modern Selenium automation framework using Java and Page Object Model (POM)—with real-world use cases from a payments application.


🧱 1. Encapsulation

 – Grouping Page Behaviors & Data

In POM, each web page is represented by a Java class. All locators and associated actions (methods) are bundled into the same class, providing encapsulation.

Example:

LoginPage.java might contain:

public class LoginPage {

    @FindBy(id="username")

    private WebElement usernameInput;


    @FindBy(id="password")

    private WebElement passwordInput;


    @FindBy(id="loginBtn")

    private WebElement loginButton;


    public void login(String user, String pass) {

        usernameInput.sendKeys(user);

        passwordInput.sendKeys(pass);

        loginButton.click();

    }

}

This hides internal mechanics from external classes, exposing only the method login()—a clean interface for test classes.


🧬 2. Inheritance

 – Reusability of Test Utilities

Inheritance is used to extend common functionality across test components like base test setup, common utilities, or driver management.

Example:

public class BaseTest {

    protected WebDriver driver;


    @BeforeMethod

    public void setup() {

        driver = new ChromeDriver();

        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));

    }


    @AfterMethod

    public void tearDown() {

        driver.quit();

    }

}

Then, individual test classes inherit this:

public class LoginTests extends BaseTest {

    @Test

    public void testValidLogin() {

        new LoginPage(driver).login("user", "pass");

        // assertions

    }

}

🎭 3. Polymorphism

 – Interface-Based Design

Polymorphism allows flexible and scalable design, especially when using interface-driven development.

Use Case: Suppose your framework needs to support both Chrome and Firefox.

public interface DriverManager {

    WebDriver getDriver();

}

Concrete implementations:

public class ChromeManager implements DriverManager {

    public WebDriver getDriver() {

        return new ChromeDriver();

    }

}


public class FirefoxManager implements DriverManager {

    public WebDriver getDriver() {

        return new FirefoxDriver();

    }

}

Now, switching browsers is easy without changing test logic:

DriverManager manager = new ChromeManager(); // or FirefoxManager

WebDriver driver = manager.getDriver();


🧩 4. Abstraction

 – Hiding Implementation Behind Layers

Abstraction is used in frameworks via utility and wrapper classes to hide the complexity of Selenium commands.

Example: Create a utility method for dropdown handling:

public class DropdownUtils {

    public static void selectByVisibleText(WebElement dropdown, String text) {

        new Select(dropdown).selectByVisibleText(text);

    }

}

Now testers use just:

DropdownUtils.selectByVisibleText(dropdownElement, "United States");

This hides internal logic and improves readability.


🏁 Final Thoughts

OOPS principles are not just theoretical—they are the foundation of real-world, enterprise-grade test automation frameworks. By applying:

  • Encapsulation (clean page classes),

  • Inheritance (shared test logic),

  • Polymorphism (browser/interface abstractions), and

  • Abstraction (utility layers),

you build a test architecture that’s scalable, readable, and easily maintainable.

This approach isn’t limited to Selenium. You can apply the same mindset in API testing frameworks, Appium, Playwright, and beyond.

🚀 Turbo Intruder: Unleashing High-Speed Race Condition Testing with Burp Suite


When it comes to identifying race conditions and testing concurrency issues in APIs, Turbo Intruder is a must-have weapon in your offensive security toolkit. This powerful Burp Suite extension is built to launch blazing-fast HTTP requests—ideal for race condition exploits that require precise timing and volume.

Here’s a quick guide to getting started:


🛠️ Setting Up Turbo Intruder in Burp Suite

Step 1: Launch Burp Suite and go to the top menu → Extensions.

Step 2: In the Extensions tab, click BApp Store.

Step 3: Search for Turbo Intruder, then click Install.


⚙️ Running Your First Attack

Once installed, it’s time to get hands-on:

  • Select any API request in Burp’s HTTP history or Repeater.

  • Right-click the request → Navigate to Extensions > Turbo Intruder > Send to Turbo Intruder.

🧩 Customize the Request

  • Insert a %s token into any part of the request (e.g., a header or query parameter) where you want to inject payloads.

  • Scroll down to the scripting panel and modify the Python script to control how the payloads are fired—sequentially, concurrently, or in bursts.

 💥 Launch the Attack

  • Click Attack to fire off the customized payloads at high speed.

  • Analyze the results to detect anomalies that signal race conditions or concurrency flaws.

🔍 Why Turbo Intruder?

  • Speed: It outpaces traditional Burp tools with asynchronous, multi-threaded requests.

  • Control: Fine-grained scripting lets you simulate real-world race conditions.

  • Visibility: Detailed results make it easier to identify timing-related bugs.

🧠 Pro Tip

Race conditions often result in subtle, non-deterministic behavior. Run attacks multiple times and compare response patterns. Look out for HTTP 409, duplicated resources, or unauthorized access anomalies.


Try it out and take your API security testing to the next level!

Let me know your experience with Turbo Intruder or drop your favorite race condition use case in the comments 👇


My Profile

My photo
can be reached at 09916017317