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:
A 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.
No comments:
Post a Comment