Building Selenium based automation framework using Java OOPS concepts
Building a Selenium automation framework requires a strong foundation in Object-Oriented Programming (OOP) principles. By incorporating OOPs concepts like encapsulation, inheritance, abstraction, and polymorphism, we can create a scalable, maintainable, and reusable framework.
This blog explores best practices for building such a framework using Selenium, TestNG, and Java.
Let’s learn about these OOPs concepts and incorporate them into the automation framework.
What are Object-Oriented Programming (OOP) principles and how they matter in automation frameworks?
Key concepts of OOPS :
Encapsulation
Inheritance
Abstraction
Polymorphism
Class
Class is a user-defined data type, which holds data members and member functions and can be accessed by creating an instance of that class. It’s like a blueprint for an object.
class Car { // Properties (data members) int wheels; int speedLimit; // Constructor to initialize the properties public Car(int wheels, int speedLimit, double mileage) { this.wheels = wheels; this.speedLimit = speedLimit; } // Method to display car details(member function) public void displayDetails() { System.out.println("Wheels: " + wheels); System.out.println("Speed Limit: " + speedLimit + " km/h"); } } |
Object
An object is an instance of a class. Data members and methods of a class cannot be used directly. We need to create an object (or instance) of the class to use them. In simple terms, they are the actual world entities that have a state and behavior.
public class Main { public static void main(String[] args) { // Create a Car object Car camry = new Car(4, 200, 15.5); // Display car details System.out.println(" Camry Details:"); camry.displayDetails(); } } |
Encapsulation
Encapsulation is a process of binding the data members (attributes) and member functions together. It restricts direct access to important data.
The best example of the encapsulation concept is making the data members of a class private, and methods as public to access through an object. In this case, only methods can access private data.

// Java Program to demonstrate- Encapsulation class Person {
// Encapsulating the name and age // only approachable and used using methods private String name; private int age;
public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } | public class Main { public static void main(String[] args) { Person personObj = new Person(); // person object created person.setName("John"); person.setAge(30); // Using methods to get the values from the variables System.out.println("Name: " + person.getName()); System.out.println("Age: " + person.getAge()); } }
|
Inheritance
Inheritance is a process by which we can reuse the functionalities of existing classes to new classes. When a class is inherited from another class (base class/Super class), it (derived class/Sub class) obtains all the properties and behaviors of the base class.

class Animal { public void eat() { System.out.println("Animal is eating"); } } class Dog extends Animal { public void bark() { System.out.println("Dog is barking"); } } public class Main { public static void main(String[] args) { Dog myDog = new Dog(); myDog.eat(); // Inherited from Animal // Animal is eating myDog.bark(); // Specific to Dog // Dog is barking } } |
Abstraction
Abstraction focuses on hiding the implementation details and exposing only the essential features.

public abstract class Shape { abstract void draw(); } public class Circle extends Shape { @Override void draw() { System.out.println("Drawing a circle"); }} public class Rectangle extends Shape { @Override void draw() { System.out.println("Drawing a rectangle"); } } public class Main { public static void main(String[] args) { Shape obj = new Circle(); obj.draw(); // Outputs “Drawing a circle” obj = new Rectangle(); obj.draw(); // Outputs “Drawing a rectangle” } } |
Polymorphism
The term "polymorphism" means "many forms". In object-oriented programming, polymorphism is useful when you want to create multiple forms with the same name of a single entity.
class Animal { public void animalSound() { System.out.println("The animal makes a sound"); }}class Pig extends Animal { @Override public void animalSound() { System.out.println("The pig says: wee wee"); }}class Dog extends Animal { @Override public void animalSound() { System.out.println("The dog says: woof woof");} } | public class PolymorphismExample { public static void main(String[] args) { Animal animal = new Animal(); animal.makeSound(); //the animal makes sounds Dog dog = new Dog(); dog.makeSound(); //the dog barks animal = new Cat(); animal.makeSound(); //the cat meows } } |
Here’s how each OOP concept applies to Selenium automation frameworks:
TestNG framework

Encapsulation: Groups related actions and data into classes, making the code modular and easy to manage.
Example : SignInPage.java class from the above framework, we can achieve encapsulation by declaring the web elements as private and methods accessing these elements as public.

Inheritance: Enables code reuse by allowing test classes to inherit common behaviors from a base class.
Example : SignInPageEvents.java class inherits setUP and tearDown methods from the Base class and executes before and after each @Test methods.
![]() | ![]() |
Polymorphism: Provides flexibility to handle multiple implementations through method overriding or interfaces.
Example: In BrowserFactory.java class, WebDriver is an interface in Selenium. ChromeDriver, FirefoxDriver, and EdgeDriver are concrete classes that implement the WebDriver interface.By using WebDriver as the return type and assigning instances of ChromeDriver, FirefoxDriver, or EdgeDriver to it, the method exhibits runtime polymorphism. This allows the code to work with any browser driver that implements the WebDriver interface, making it flexible and extensible.
![]() |
Abstraction: Simplifies complex logic by exposing only essential details, keeping the rest hidden.
Example: ReportGenerator.java is abstract base class that defines a high-level blueprint for generating reports with the abstract method generateReport() , this method has no implementation. The subclasses that extends this abstract class can have the implementation for the method generateReport(). This is how abstraction hides the specifics of how reports (e.g., HTML or PDF) are generated, while requiring subclasses to provide their own implementation.
![]() | ![]() ![]() |
The complete code for this Selenium TestNg framework is available on my GitHub repository. [👉 View the Project on GitHub (https://github.com/geetak23/OOPs_Demo_Prj) ]
Building Selenium Java framework using OOP concepts ensures scalability, maintainability, and reusability. Start small, iterate as needed, and continuously enhance your framework with advanced features.
I hope you found this blog as insightful and enjoyable to read as I did while writing it. Happy learning!








