DEV Community

Utkarsh
Utkarsh

Posted on

Day 04 - 🧩 Building a Complete Selenium Java Framework - Base Class Refactoring & TestNG Suite Integration

Day 04 – Base Class Refactoring & TestNG Suite Integration

By Day 03, we had a working Base Class that could:

  • Launch a browser
  • Read configuration values
  • Open the application
  • Close the browser

On Day 04, we make this code production-ready.

Today is about:

  • Refactoring (cleaning and modularising code)
  • Optimising TestNG lifecycle usage
  • Introducing TestNG XML for suite-level execution

This is the point where our framework starts to feel professional.


🎯 Why Refactoring Is Necessary

As frameworks grow:

  • One long method becomes hard to debug
  • Changes in one place can break others
  • Reusability drops

Refactoring helps us:

  • Split responsibilities
  • Improve readability
  • Prepare for parallel execution later

πŸ‘‰ Rule of thumb:
Small methods, single responsibility.


Step 1: Refactoring the Base Class (Modern Approach)

πŸ”§ Key Improvements from Day 03

βœ” Load configuration once per suite
βœ” Separate browser launch and configuration
βœ” Avoid unnecessary static waits
βœ” Prepare for cross-browser and parallel execution


πŸ“ Updated File Location

src/main/java
 └── com.orangehrm.base
     └── BaseClass.java
Enter fullscreen mode Exit fullscreen mode

βœ… Refactored BaseClass.java (Industry Standard)

package com.orangehrm.base;

import java.io.FileInputStream;
import java.time.Duration;
import java.util.Properties;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;

import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;

public class BaseClass {

    protected static Properties prop;
    protected WebDriver driver;

    // Load configuration only once before suite execution
    @BeforeSuite
    public void loadConfig() {
        try {
            prop = new Properties();
            FileInputStream fis = new FileInputStream(
                System.getProperty("user.dir") + "/src/main/resources/config.properties"
            );
            prop.load(fis);
        } catch (Exception e) {
            throw new RuntimeException("Failed to load config.properties", e);
        }
    }

    // Runs before every test method
    @BeforeMethod
    public void setup() {
        launchBrowser();
        configureBrowser();
    }

    // Browser initialization
    private void launchBrowser() {
        String browser = prop.getProperty("browser").toLowerCase();

        switch (browser) {
            case "chrome":
                driver = new ChromeDriver(); // Selenium Manager handles driver
                break;

            case "firefox":
                driver = new FirefoxDriver();
                break;

            case "edge":
                driver = new EdgeDriver();
                break;

            default:
                throw new RuntimeException("Unsupported browser: " + browser);
        }
    }

    // Browser configuration
    private void configureBrowser() {
        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(
            Duration.ofSeconds(Integer.parseInt(prop.getProperty("implicit_wait")))
        );
        driver.get(prop.getProperty("url"));
    }

    // Runs after every test method
    @AfterMethod
    public void tearDown() {
        if (driver != null) {
            driver.quit();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ” Important Corrections & Best Practices

❌ Why We Removed LockSupport / Static Waits

  • Hard waits are not recommended in modern frameworks
  • They block execution unnecessarily
  • We will rely on explicit waits inside the Action Driver (Day 05)

πŸ‘‰ Static waits should only be used for debugging, not framework design.


βœ… Why @BeforeSuite Is Used for Config

  • Configuration data is global
  • Loading it once improves performance
  • Prevents repeated file I/O operations

⚠ Why WebDriver Is NOT Static

  • Static WebDriver breaks parallel execution
  • Causes session conflicts
  • Modern frameworks use instance-level drivers

Parallel execution will be introduced later using ThreadLocal.


Step 2: Introducing TestNG XML (Suite Control Center)

So far, we ran tests by right-clicking test classes.
In real projects, this is never done.

Instead, we use TestNG XML to:

  • Group tests
  • Control execution order
  • Enable parallel runs
  • Integrate with CI/CD

πŸ“„ Create testng.xml

Location (recommended):

src/test/resources/testng.xml
Enter fullscreen mode Exit fullscreen mode

🧾 testng.xml (Clean & Correct)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">

<suite name="OrangeHRM Automation Suite">

    <test name="Smoke Tests">
        <classes>
            <class name="com.orangehrm.tests.DummyTest"/>
        </classes>
    </test>

</suite>
Enter fullscreen mode Exit fullscreen mode

Step 3: Running Tests Using TestNG XML

β–Ά How to Run

  • Right-click testng.xml
  • Select Run As β†’ TestNG Suite

βœ… Expected Flow

  1. Config loads once
  2. Browser launches before each test
  3. Application opens
  4. Test executes
  5. Browser closes cleanly

This is exactly how CI tools like Jenkins run tests.


πŸ“Œ Day 04 Summary

Today, you:

  • Refactored the Base Class for scalability
  • Applied TestNG lifecycle correctly
  • Introduced suite-based execution
  • Prepared the framework for future growth

Your framework is no longer β€œbasic automation” β€”
it is now architected.


🧠 Day 04 Task

  1. Refactor your BaseClass as shown
  2. Create testng.xml
  3. Add DummyTest to the suite
  4. Run tests using TestNG Suite, not individual classes

πŸš€ What’s Coming Next (Day 05)

Next, we will build the Action Driver:

  • click()
  • sendKeys()
  • explicit waits
  • element visibility handling

This will make test scripts:
βœ” Smaller
βœ” Cleaner
βœ” Easier to read

You’ve officially crossed into framework engineering territory πŸ‘

Top comments (0)