An Overview of Selenium Framework Architecture

Samiksha KuteSamiksha Kute
5 min read

If you want to deeply understand how a real-world Selenium framework works, this guide is for you. We’re going to walk through a complete framework architecture and explain every part of it clearly, step-by-step.

This architecture is based on a modular, maintainable, and scalable design pattern that many real-time projects follow. It's also perfect to draw and explain during interviews!

Overview of the Framework Flow

At a high level, this is how the framework works:

  • Test cases execute test steps.

  • Test steps interact with web elements via locators.

  • Locators are stored in Page Objects.

  • Reusable methods are centralized in an Abstract Component.

  • Test cases are managed and configured via XML files.

  • Data for test execution comes from JSON files.

  • Reporting and screenshots are handled via Listeners.

  • The entire setup is executed via Maven commands using the pom.xml.

Let’s break down each part one by one.

1. Test Cases: The Heart of Execution

At the center of your framework are the test cases. Each test case contains the steps needed to validate specific scenarios in your application.

Example test cases:

  • TestCase1

  • TestCase2

  • TestCase3

But these test steps need locators. So, where do the locators come from?

2. Page Objects: Source of Locators

All the locators (like buttons, inputs, links, etc.) that your test cases use are stored in Page Object classes.

If your application has 10 pages, you will have 10 corresponding page object classes - one for each page.

Example:

  • LoginPage.java

  • ProductPage.java

  • CartPage.java

Each page class holds the element locators and page-level methods. The test cases access elements through these classes, following the Page Object Model (POM) design pattern.

3. Abstract Component: Reusable Methods for Pages

Some methods are common across multiple pages - for example:

  • Waiting for elements

  • Navigating to the cart

  • Handling headers/footers

Instead of duplicating these methods in every page class, we create a common abstract class, usually named something like AbstractComponent.java.

How it works:

  • All Page Object classes extend this abstract class.

  • Shared utilities (e.g., waits, navigations) live in AbstractComponent.

  • This promotes code reusability and keeps the code DRY (Don’t Repeat Yourself).

4. Base Test: Reusable Setup Code for Test Cases

Just like page objects have reusable utilities, test cases also need common code, such as:

  • Opening the browser

  • Closing the browser

  • Choosing which browser to run

All this setup and teardown logic is moved into a Base Test class (e.g., BaseTest.java).

Key point:

All test classes extend the BaseTest class to inherit browser and environment setup code.

So,

  • Page Object classes ⟶ extend AbstractComponent

  • Test classes ⟶ extend BaseTest

5. Test Data: Provided from JSON Files

Your test cases need input data. Instead of hardcoding this, we externalize it using JSON files.

How it works:

  1. JSON files hold test data (like usernames, product names, etc.).

  2. In the BaseTest, a parser method (like getDataToJson()) reads the JSON file.

  3. This method converts the data into a HashMap.

  4. A DataProvider uses this HashMap to supply data to each test.

This way, your data is separated from your tests, supporting data-driven testing.

6. Reporting and Screenshots: Handled by Listeners

For tracking results and failures, we use TestNG Listeners.

Listeners perform actions before and after each test:

  • Create entries in the Extent HTML Report

  • Take screenshots on failure

  • Log test status (pass/fail)

Flow:

  1. Test starts → Listener creates an Extent Report entry.

  2. Test executes.

  3. Test ends → Listener updates the report with pass/fail status and screenshot.

This improves visibility and debugging by generating beautiful HTML reports.

7. Retry Mechanism: Retry Listener

Sometimes tests fail due to flakiness (like timing issues). To handle this, we use a Retry Listener.

It automatically reruns failed tests based on configuration, improving reliability in CI pipelines.

This is also part of the listener setup and helps reduce false negatives in reports.

8. XML Files: The Test Runners

The execution of tests is triggered through TestNG XML files. These XML files decide:

  • Which test classes to run

  • In what order

  • With what groups or parameters

Example:

  • testng-smoke.xml

  • testng-regression.xml

9. POM.xml and Maven: The Entry Point

Tests are triggered using Maven commands via the terminal.

Flow:

  1. You run a Maven command.

  2. It reads the pom.xml file.

  3. Inside pom.xml, we define profiles for different TestNG XMLs.

  4. Based on the profile, the corresponding TestNG XML is triggered.

  5. That XML file runs the listed test cases.

10. Execution Flow: Bringing it All Together

Let’s visualize how everything flows:

  1. You run a Maven command.

  2. Maven checks pom.xml and chooses the correct TestNG XML.

  3. TestNG XML specifies the test cases to run.

  4. Test cases:

    • Use BaseTest to set up browser

    • Get data from JSON via getDataToJson() parser

    • Use Page Objects for UI interaction

  5. Page Objects access AbstractComponent for reusable actions.

  6. Listeners capture reports/screenshots.

  7. Final Extent HTML Report is generated.

11. Advanced Concepts

To further strengthen your framework, mention the following advanced features:

Inheritance and Interfaces

  • Page classes extend AbstractComponent

  • Test classes extend BaseTest

  • Interface implementations are used for abstraction and modularity

Thread Local Group for Parallel Execution

  • Inside listeners, we use ThreadLocal to maintain thread safety.

  • This allows parallel test execution without conflict.

Cucumber Integration (Optional Layer)

If you're using Cucumber, your framework may also have:

  • Feature files

  • Step Definitions
    These can act as a wrapper over the test cases for BDD-style scenarios.

Final Thoughts

This framework (check out the previous blogs for complete framework design) is designed using best practices in test automation:

  • Follows the Page Object Model

  • Promotes code reuse with inheritance

  • Supports data-driven testing with JSON

  • Generates professional HTML reports

  • Handles failures with retry and screenshots

  • Enables parallel execution with ThreadLocal

0
Subscribe to my newsletter

Read articles from Samiksha Kute directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Samiksha Kute
Samiksha Kute

Passionate Learner!