Building a Modular Selenium Framework in Java
A modular Selenium framework makes automated testing scalable, maintainable, and reusable. Instead of writing tests in a messy, repetitive way, a modular framework organizes code into logical modules.
This guide explains:
Key design principles
Must-have components
Recommended folder structure
Using Page Object Model (POM)
Adding utilities & reusable modules
Test execution setup (TestNG/JUnit)
Sample code snippets
Best practices
✅ 1. Principles of a Modular Selenium Framework
A good Selenium framework MUST follow these concepts:
✔️ DRY (Don’t Repeat Yourself)
Avoid duplicated test code.
✔️ Separation of Concerns
Keep test logic, locators, utilities, and configurations separate.
✔️ Reusable Components
Actions, drivers, waits, logging, assertions.
✔️ Maintainability
Updating a locator should NOT require changing every test.
✔️ Extensibility
Easy to add new modules and test scenarios.
๐️ 2. Recommended Folder Structure
A clean, modular structure (Maven project):
src
├── main
│ ├── java
│ │ ├── base
│ │ │ └── BaseTest.java
│ │ ├── pages
│ │ │ └── LoginPage.java
│ │ ├── utils
│ │ │ ├── DriverFactory.java
│ │ │ ├── ConfigReader.java
│ │ │ └── WaitUtils.java
│ │ └── enums
│ └── resources
│ └── config.properties
└── test
├── java
│ └── tests
│ └── LoginTest.java
└── resources
⚙️ 3. Core Components of the Framework
Your modular framework should include:
1️⃣ Driver Management
Selenium WebDriver initialization
Browser selection
Thread-safe driver for parallel execution
2️⃣ Page Object Model (POM)
Each page = a dedicated class
Encapsulates:
Locators
Page actions
Validations
3️⃣ Utilities
Reusable helper methods:
Waits
Logging
Screenshots
Excel/JSON readers
4️⃣ Configuration Management
Store reusable settings in:
config.properties
Example:
baseURL=https://example.com
browser=chrome
timeout=10
5️⃣ Test Runner
Using TestNG or JUnit for:
Test execution
Groups
Assertions
Reporting
๐ 4. Driver Factory Example (Singleton + ThreadLocal)
public class DriverFactory {
private static ThreadLocal<WebDriver> driver = new ThreadLocal<>();
public static WebDriver getDriver() {
return driver.get();
}
public static void initDriver(String browser) {
if (browser.equalsIgnoreCase("chrome")) {
driver.set(new ChromeDriver());
}
driver.get().manage().window().maximize();
}
public static void quitDriver() {
driver.get().quit();
driver.remove();
}
}
This enables parallel test execution safely.
๐ 5. Base Test Class
public class BaseTest {
@BeforeMethod
@Parameters("browser")
public void setUp(String browser) {
DriverFactory.initDriver(browser);
DriverFactory.getDriver().get(ConfigReader.getProperty("baseURL"));
}
@AfterMethod
public void tearDown() {
DriverFactory.quitDriver();
}
}
All test classes extend BaseTest.
๐งฑ 6. Page Object Model (POM)
Example: LoginPage.java
public class LoginPage {
private WebDriver driver;
@FindBy(id="username")
private WebElement username;
@FindBy(id="password")
private WebElement password;
@FindBy(id="loginBtn")
private WebElement loginBtn;
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public void enterUsername(String user) {
username.sendKeys(user);
}
public void enterPassword(String pass) {
password.sendKeys(pass);
}
public void clickLogin() {
loginBtn.click();
}
}
๐งช 7. Test Class Example
public class LoginTest extends BaseTest {
@Test
public void validLoginTest() {
LoginPage loginPage = new LoginPage(DriverFactory.getDriver());
loginPage.enterUsername("admin");
loginPage.enterPassword("12345");
loginPage.clickLogin();
Assert.assertTrue(DriverFactory.getDriver().getTitle().contains("Dashboard"));
}
}
This test is clean because all logic lives in page classes and utilities.
๐งฐ 8. Utilities (Example)
WaitUtils.java
public class WaitUtils {
public static WebElement waitForElement(WebDriver driver, By locator, int timeout) {
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(timeout));
return wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
}
}
ConfigReader.java
public class ConfigReader {
private static Properties properties = new Properties();
static {
try (InputStream input = new FileInputStream("config.properties")) {
properties.load(input);
} catch (Exception e) {
e.printStackTrace();
}
}
public static String getProperty(String key) {
return properties.getProperty(key);
}
}
๐ 9. Reporting Tools
Integrate:
ExtentReports
Allure Reports
TestNG HTML reports
These give insights into passed/failed tests, screenshots, logs, and timing.
๐งฑ 10. Best Practices for a Modular Selenium Framework
✔️ Use Page Object Model (POM)
Keep locators and methods grouped logically.
✔️ Use Page Factory or By locators consistently
Avoid mixing patterns.
✔️ Parameterize Test Data
Use JSON, CSV, Excel, or external data providers.
✔️ Keep test classes extremely small
Logic belongs in pages & utilities, not in the test itself.
✔️ Enable parallel execution
Use ThreadLocal WebDriver.
✔️ Use Maven or Gradle for dependency management
✔️ Maintain a clear naming convention
๐ Conclusion
A modular Selenium framework in Java makes test automation:
Clean
Organized
Scalable
Maintainable
Reusable
By using POM, utilities, driver factories, and structured tests, your framework becomes robust enough for real-world enterprise test automation.
Learn Selenium with JAVA Training in Hyderabad
Read More
๐งฑ Framework Building & Design
Using Config Files for Environment Management
Reading Environment Variables in Selenium Tests
Using HashMap and ArrayList to Store Test Data
Visit Our Quality Thought Institute in Hyderabad
Subscribe by Email
Follow Updates Articles from This Blog via Email
No Comments