In many Selenium interviews, you may come across a common question: "Where have you applied OOPs (Object-Oriented Programming) concepts in an Automation Framework?" This question aims to assess your understanding and practical implementation of OOPs principles in the context of test automation. Before delving into the specifics of applying OOPs concepts in an Automation Framework, it is essential to have a solid understanding of OOPs concepts in Java.
In this article, we will explore and elaborate on how and where we have applied various OOPs concepts in an Automation Framework. The Automation Framework refers to the structural and functional architecture that is built to support automated testing. By understanding and applying OOPs principles effectively, we can design a robust and maintainable Automation Framework that leverages the advantages of object-oriented programming.
OOPs concepts, such as encapsulation, inheritance, polymorphism, and abstraction, play a crucial role in designing and implementing an Automation Framework. These concepts allow for modular code organisation, code reuse, flexibility, and maintainability. We will explore examples and scenarios where each OOPs concept is applied to enhance the effectiveness and efficiency of an Automation Framework.
By understanding how OOPs concepts are utilised in an Automation Framework, you can demonstrate your proficiency in applying object-oriented principles to create well-structured and scalable test automation solutions. This knowledge will not only help you answer interview questions but also enable you to design and implement robust Automation Frameworks in your professional projects.
Abstraction is a methodology of hiding the implementation and displaying the functionality to end users.
Let’s understand with an example:
In Page Object Model design pattern, we write locators (such as Id, Name, Xpath, etc. ) and the methods in a Page class. Then we utilise these locators and methods in tests but we can’t see the implementation of the methods.
In Java, abstraction is achieved by interfaces and abstract classes. Using interfaces, we can achieve 100% abstraction.
Example:
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
// Abstract Page class
public abstract class Page {
protected WebDriver driver;
public Page(WebDriver driver) {
this.driver = driver;
}
// Abstract method to be implemented by child classes
public abstract WebElement getElement(By locator);
// Abstract method to be implemented by child classes
public abstract void clickElement(By locator);
}
// Concrete Page class
public class HomePage extends Page {
public HomePage(WebDriver driver) {
super(driver);
}
@Override
public WebElement getElement(By locator) {
return driver.findElement(locator);
}
@Override
public void clickElement(By locator) {
WebElement element = getElement(locator);
element.click();
}
// Additional methods specific to the Home page can be defined here
}
// Test class
public class TestAbstraction {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
HomePage homePage = new HomePage(driver);
homePage.clickElement(By.id("loginButton"));
}
}
We all are aware of this statement
WebDriver driver = new FirefoxDriver();
Here WebDriver is an Interface. In the above statement, we are initialising the Firefox browser using Selenium WebDriver (Interface).
It means we are creating a reference variable (driver) of the interface (WebDriver) and creating an object of FirefoxDriver class.
Note: An interface looks similar to a class but actually both different concepts. An interface can have methods and variables just like the class but the methods declared in the interface are by default abstract.
Note: We can achieve 100% abstraction and multiple inheritance in Java with Interface.
Mechanism by which one class acquires the properties (instance variables) and functionalities of another class is known as Inheritance.
Base Class in the Automation Framework is used to initialise the WebDriver interface, WebDriver waits, Property files, Excels, etc. in the Base class.
We extend the Base class to other classes such as Tests and Utility class.
Example:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
// Base class
public class BaseClass {
protected WebDriver driver;
public BaseClass() {
// Initialize WebDriver, waits, property files, etc.
driver = new ChromeDriver();
}
// Common methods and functionalities can be defined here
}
// Test class
public class TestClass extends BaseClass {
public void performTest() {
// Access the WebDriver and other resources from the BaseClass
driver.get("https://www.example.com");
// Perform test-specific actions
}
}
// Utility class
public class UtilityClass extends BaseClass {
public void performUtilityTask() {
// Access the WebDriver and other resources from the BaseClass
driver.manage().window().maximize();
// Perform utility-specific actions
}
}
Polymorphism allows us to perform a task in multiple ways.
A combination of overloading and overriding is known as Polymorphism.
Let's understand overloading and overriding in details.
We use Implicit wait in Selenium. The implicit wait is an example of overloading.
In Implicit wait, we use different time stamps such as SECONDS, MINUTES, HOURS, etc.,
Action class in TestNG is also an example of overloading.
Assert class in TestNG is also an example of overloading.
A class having multiple methods with the same name but different parameters are called Method Overloading.
Examples:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.concurrent.TimeUnit;
public class ImplicitWaitExample {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
implicitWait(driver, 10); // Implicit wait in seconds
driver.get("https://www.example.com");
}
// Method overloading for implicit wait with seconds
public static void implicitWait(WebDriver driver, int seconds) {
driver.manage().timeouts().implicitlyWait(seconds, TimeUnit.SECONDS);
}
// Method overloading for implicit wait with minutes
public static void implicitWait(WebDriver driver, int minutes) {
driver.manage().timeouts().implicitlyWait(minutes, TimeUnit.MINUTES);
}
}
We use a method that was already implemented in another class by changing its parameters. To understand this you need to understand Overriding in Java.
Declaring a method in a child class that is already present in the parent class is called Method Overriding.
Example:
// Parent class
class WebDriver {
public void click() {
System.out.println("Clicking on element");
}
}
// Child class
class ChromeDriver extends WebDriver {
@Override
public void click() {
System.out.println("Performing click action using ChromeDriver");
// Additional steps specific to ChromeDriver
}
}
// Test class
public class TestAutomation {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
driver.click(); // This will call the overridden click method in ChromeDriver
}
}
All the classes in a framework are an example of Encapsulation.
In POM classes, we declare the data members using @FindBy, and initialization of data members will be done using Constructor to utilise those in methods.
Encapsulation is a mechanism of binding code and data (variables) together in a single unit.
Example:
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
// POM class
public class LoginPage {
@FindBy(id = "usernameInput")
private WebElement usernameInput;
@FindBy(id = "passwordInput")
private WebElement passwordInput;
@FindBy(id = "loginButton")
private WebElement loginButton;
private WebDriver driver;
public LoginPage(WebDriver driver) {
this.driver = driver;
}
public void setUsername(String username) {
usernameInput.sendKeys(username);
}
public void setPassword(String password) {
passwordInput.sendKeys(password);
}
public void clickLoginButton() {
loginButton.click();
}
}
In the example above, we have a `LoginPage` class that represents a page in an Automation Framework using the POM design pattern. This class encapsulates the login functionality of the page.
The data members (variables) of the class, such as `usernameInput`, `passwordInput`, and `loginButton`, are declared using the `@FindBy` annotation, which is a feature of Selenium's PageFactory. This annotation helps in locating and initialising the elements on the page using locators like ID, CSS, XPath, etc.
The `WebDriver` instance is also encapsulated within the class as a private data member. It is passed to the class through the constructor, ensuring that the class has access to the necessary browser driver.
The methods `setUsername`, `setPassword`, and `clickLoginButton` provide an interface to interact with the elements on the login page. These methods encapsulate the implementation details of finding the elements and performing actions on them.
By encapsulating the elements and the WebDriver instance within the `LoginPage` class, we create a single unit where the code and data (variables) are bound together. This allows for better organization, reusability, and maintenance of the code. Other classes in the framework can then utilize the `LoginPage` class to perform login-related actions without worrying about the internal details.
Encapsulation, as demonstrated in this example, is a fundamental principle of object-oriented programming that promotes modularity, data hiding, and code organization in the development of an Automation Framework.
In conclusion, the article provides insights into the practical application of Object-Oriented Programming (OOPs) concepts in an Automation Framework. By exploring various OOPs principles such as encapsulation, inheritance, polymorphism, and abstraction, the article helps readers understand the significance of these concepts in designing a robust and maintainable Automation Framework. By applying OOPs concepts effectively, developers can achieve modularity, code reusability, flexibility, and scalability in their test automation solutions. Understanding and implementing OOPs concepts in an Automation Framework will not only aid in answering interview questions but also empower individuals to create well-structured and efficient test automation frameworks in their professional projects.