0% found this document useful (0 votes)
5 views

Why Selenium WebDriver is an Interface

Selenium

Uploaded by

Gilvan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views

Why Selenium WebDriver is an Interface

Selenium

Uploaded by

Gilvan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 14

Why Selenium WebDriver is an

Interface: Comprehensive Explanation


Core Idea of an Interface

An interface defines a set of rules that multiple classes must follow, but it does not define
how the rules are implemented. Selenium WebDriver uses this principle to ensure that all
browser drivers (like ChromeDriver, FirefoxDriver, etc.) follow the same rules (methods like
get(), findElement(), etc.) while allowing each driver to provide its own implementation of
these methods.

Let’s dive into the details with real-world analogies, comparative examples, and code
illustrations.

Real-World Analogy: A Taxi Service

Imagine a global taxi service standard defines three actions:

1. Start the car


2. Drive to a location
3. Stop the car

Now, whether the taxi is a Toyota, BMW, or Tesla, the process remains the same at a high
level: start, drive, and stop. However, the implementation differs:

● Toyota: A conventional gas engine requires turning a key to start.


● BMW: A luxury car may have a push-button start.
● Tesla: An electric car may start automatically when you sit in the driver's seat.

In Selenium:

● WebDriver is the standard (interface) that defines the methods every browser
driver must have, such as get(), findElement(), and quit().
● Browser drivers like ChromeDriver, FirefoxDriver, etc., implement these methods
differently based on the browser's internal structure.
Example in Code
// Define the interface
interface Taxi {
void startCar();
void driveToLocation(String location);
void stopCar();
}

// Toyota implements Taxi


class Toyota implements Taxi {
public void startCar() {
System.out.println("Insert the key and turn to start the Toyota.");
}
public void driveToLocation(String location) {
System.out.println("Driving to " + location + " using a
conventional gas engine.");
}
public void stopCar() {
System.out.println("Turn off the engine and remove the key.");
}
}

// Tesla implements Taxi


class Tesla implements Taxi {
public void startCar() {
System.out.println("Car starts automatically when the driver sits
in the seat.");
}
public void driveToLocation(String location) {
System.out.println("Driving to " + location + " using electric
autopilot.");
}
public void stopCar() {
System.out.println("Car shuts down when the driver leaves the
seat.");
}
}

// Usage
public class TaxiService {
public static void main(String[] args) {
Taxi toyotaTaxi = new Toyota();
toyotaTaxi.startCar();
toyotaTaxi.driveToLocation("Airport");
toyotaTaxi.stopCar();

System.out.println();

Taxi teslaTaxi = new Tesla();


teslaTaxi.startCar();
teslaTaxi.driveToLocation("Hotel");
teslaTaxi.stopCar();
}
}

Output:
Insert the key and turn to start the Toyota.
Driving to Airport using a conventional gas engine.
Turn off the engine and remove the key.

Car starts automatically when the driver sits in the seat.


Driving to Hotel using electric autopilot.
Car shuts down when the driver leaves the seat.

How Implementation Differs:

● The startCar() method is implemented differently for Toyota and Tesla.


● Despite these differences, the user interacts with both cars through the same set
of methods (startCar(), driveToLocation(), stopCar()), defined in the Taxi interface.

In Selenium:

● WebDriver interface defines methods like get() (open a website) and quit() (close
the browser).
● Each browser driver implements these methods differently:
○ ChromeDriver: Talks to Chrome-specific APIs to navigate to a URL.
○ FirefoxDriver: Talks to Firefox-specific APIs to achieve the same.
Why WebDriver is an Interface: Technical View
1. Cross-Browser Compatibility
Using an interface allows you to write tests once and run them on multiple
browsers. The WebDriver interface ensures that all browser drivers (ChromeDriver,
FirefoxDriver, etc.) implement the same set of methods. This removes
browser-specific dependencies in your code.

Example:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;

public class CrossBrowserExample {


public static void main(String[] args) {
WebDriver driver;

// Switch between browsers dynamically


String browser = "chrome"; // or "firefox"
if (browser.equalsIgnoreCase("chrome")) {
driver = new ChromeDriver();
} else {
driver = new FirefoxDriver();
}

driver.get("https://example.com");
System.out.println("Title: " + driver.getTitle());
driver.quit();
}
}

● WebDriver driver: Declares a reference to the interface.


● ChromeDriver or FirefoxDriver: The actual implementation that handles
browser-specific behavior.
● You only need to write test logic once, regardless of the browser.

2. Code Reusability and Abstraction


The interface abstracts away the complexity of individual browser
implementations. You can focus on the test logic without worrying about how each
browser executes the operations.
Without an Interface:

ChromeDriver chrome = new ChromeDriver();


chrome.get("https://example.com");
chrome.quit();

FirefoxDriver firefox = new FirefoxDriver();


firefox.get("https://example.com");
firefox.quit();

Here, you’d need to duplicate your logic for each browser.

With an Interface:

WebDriver driver = new ChromeDriver(); // Or new FirefoxDriver();


driver.get("https://example.com");
driver.quit();

You reuse the same code for all browser drivers, making maintenance easier.

3. Ease of Switching Browsers


If Selenium WebDriver were not an interface, you’d have to rewrite your test code
for every new browser driver. Instead, with WebDriver as an interface, switching
browsers only involves changing the browser driver instantiation.

Example:

WebDriver driver = new ChromeDriver(); // For Chrome


driver.get("https://example.com");

driver = new FirefoxDriver(); // Switch to Firefox


driver.get("https://example.com");

4. Extensibility
If a new browser (say, Safari) comes into play, you don’t need to modify the
WebDriver interface or your test scripts. The new browser driver just needs to
implement the WebDriver interface.

Example:

public class SafariDriver implements WebDriver {


// Implement WebDriver methods for Safari
}

5. Polymorphism in Action
Polymorphism allows you to reference different objects (ChromeDriver,
FirefoxDriver, etc.) through the same interface (WebDriver). This reduces
complexity and makes your code flexible and scalable.

Example:

WebDriver driver = new ChromeDriver();


driver.get("https://example.com");

driver = new FirefoxDriver(); // Same reference, different implementation


driver.get("https://example.com");
Why Not Use a Class Instead of an Interface?

Core Issue with Using a Class

1. No Flexibility for Multiple Inheritances

○ Java doesn’t support multiple inheritance for classes. If WebDriver were a


class, browser drivers like ChromeDriver couldn’t extend both WebDriver
and other necessary browser-specific classes.
○ With an interface, a browser driver can implement WebDriver while still
extending another class if needed.

Example:

// Using a class (not possible with multiple inheritance)


class WebDriver {
void get(String url) {}
}
class BrowserAPI {}
class ChromeDriver extends WebDriver, BrowserAPI { // Compilation error:
Java does not allow multiple class inheritance.
}
With an Interface:

interface WebDriver {
void get(String url);
}
class BrowserAPI {}
class ChromeDriver extends BrowserAPI implements WebDriver {
public void get(String url) {
System.out.println("Navigating to " + url + " in Chrome.");
}
}

2. Rigid and Difficult to Extend

○ If WebDriver were a class, adding new browser drivers would require


modifying the WebDriver class, violating the Open/Closed Principle
(software entities should be open for extension but closed for modification).
Class Example (Rigid):

class WebDriver {
void get(String url) {
System.out.println("Default browser navigation.");
}
}
class ChromeDriver extends WebDriver {
// Cannot override get() for Chrome-specific behavior without modifying
WebDriver class.
}
Interface Example (Flexible):

interface WebDriver {
void get(String url);
}
class ChromeDriver implements WebDriver {
public void get(String url) {
System.out.println("Navigating to " + url + " in Chrome.");
}
}

Here, ChromeDriver implements its own version of get() without modifying the WebDriver
interface.

3. Polymorphism

○ With an interface, you can treat all browser drivers as a single type
(WebDriver) and switch between them easily.
○ If WebDriver were a class, this flexibility would be lost because you’d be tied
to a specific implementation.

Example with Polymorphism:

WebDriver driver = new ChromeDriver(); // Can easily switch to


FirefoxDriver.
driver.get("https://example.com");
Without Interface (Tied to a Specific Class):
ChromeDriver driver = new ChromeDriver(); // Can't switch to
FirefoxDriver.
driver.get("https://example.com");

4. Code Reusability

○ Interfaces enable reusable and clean code by separating the “what”


(defined by the interface) from the “how” (provided by the implementation).

Comparative Examples: Interface vs. Class

Using an Interface:
interface WebDriver {
void get(String url);
void quit();
}

class ChromeDriver implements WebDriver {


public void get(String url) {
System.out.println("Opening " + url + " in Chrome.");
}
public void quit() {
System.out.println("Closing Chrome browser.");
}
}

class FirefoxDriver implements WebDriver {


public void get(String url) {
System.out.println("Opening " + url + " in Firefox.");
}
public void quit() {
System.out.println("Closing Firefox browser.");
}
}

public class Test {


public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
driver.get("https://google.com");
driver.quit();

driver = new FirefoxDriver();


driver.get("https://google.com");
driver.quit();
}
}

Using a Class: Why It's Less Flexible

When we use a class for defining browser behavior, we are effectively tying our code to a
specific implementation. In contrast to an interface, a class is more rigid because it
provides both method signatures (what the methods will do) and the actual
implementation (how the methods will work). This can make the code less flexible and
harder to extend.

Let’s look at the example where WebDriver is a class instead of an interface:

// WebDriver class that defines browser-specific methods


class WebDriver {
// A method to navigate to a URL
void get(String url) {
System.out.println("Default browser navigation to " + url);
}

// A method to quit the browser


void quit() {
System.out.println("Closing the default browser.");
}
}

public class Test {


public static void main(String[] args) {
WebDriver driver = new WebDriver(); // Create an instance of
WebDriver class.
driver.get("https://google.com"); // Navigate to Google
driver.quit(); // Quit the browser
}
}
Explanation of the Code:

1. WebDriver Class:

○ The WebDriver class is defined with methods get() and quit(). These
methods perform actions that are common across browsers, such as
opening a URL and quitting the browser.
○ Since WebDriver is a class, these methods are fully implemented here, and
there's no flexibility to modify or extend them for different browser types
without changing the class itself.
2. Test Class:

○ In the Test class, an instance of WebDriver is created directly using new


WebDriver().
○ The get() method is called to open a URL, and the quit() method is called to
close the browser. However, since the WebDriver class doesn't allow for
multiple behaviors (like Chrome or Firefox specific behavior), it's limited to
the default behavior provided in the class.

Key Issues with Using a Class Here:

1. No Browser-Specific Behavior:

○ In this scenario, the class WebDriver only defines one behavior. It doesn't
account for browser-specific behavior, such as how Chrome or Firefox
handle navigation or quitting.
○ If you want to add support for Chrome or Firefox, you would have to modify
the WebDriver class itself, which could lead to messy code and potential
errors.
2. No Flexibility for Different Browser Implementations:

○ With a class, you are forced to stick to a single implementation. If you


wanted to support multiple browsers (say, ChromeDriver and FirefoxDriver),
you'd either have to create separate methods for each browser or create
multiple subclasses. This leads to code duplication and poor maintainability.

3. Tight Coupling:

○ The code is tightly coupled because the test script is directly dependent on
the WebDriver class, which doesn't allow you to easily switch to different
browser drivers without significant changes to the test code.
Example: What Happens When You Want Different Browsers?

To add support for Chrome and Firefox, we would need to create different classes, or
subclass WebDriver, which makes it harder to manage and extend. Here's a possible
approach:

// ChromeDriver extends WebDriver


class ChromeDriver extends WebDriver {
// Overriding the get method for Chrome-specific behavior
@Override
void get(String url) {
System.out.println("Opening " + url + " in Chrome.");
}

// Overriding quit method for Chrome-specific behavior


@Override
void quit() {
System.out.println("Closing Chrome browser.");
}
}

// FirefoxDriver extends WebDriver


class FirefoxDriver extends WebDriver {
// Overriding the get method for Firefox-specific behavior
@Override
void get(String url) {
System.out.println("Opening " + url + " in Firefox.");
}

// Overriding quit method for Firefox-specific behavior


@Override
void quit() {
System.out.println("Closing Firefox browser.");
}
}

public class Test {


public static void main(String[] args) {
// Create instances of different browser drivers
WebDriver chromeDriver = new ChromeDriver(); // ChromeDriver
object
chromeDriver.get("https://google.com"); // Chrome-specific
behavior
chromeDriver.quit(); // Chrome-specific quit

WebDriver firefoxDriver = new FirefoxDriver(); // FirefoxDriver


object
firefoxDriver.get("https://google.com"); // Firefox-specific
behavior
firefoxDriver.quit(); // Firefox-specific
quit
}
}

Output:
Opening https://google.com in Chrome.
Closing Chrome browser.
Opening https://google.com in Firefox.
Closing Firefox browser.

Why This is Problematic:

1. Code Duplication:
We end up duplicating the behavior of get() and quit() for every browser. If we
wanted to add a new browser, we would have to write another subclass and repeat
the behavior.

2. Inheritance Limitations:
Java doesn't support multiple inheritance for classes, so if ChromeDriver needs to
inherit behavior from other classes (like BrowserAPI), it would be problematic. You
can't extend more than one class.

3. No Polymorphism:
If we want to switch browsers in the test code, we'd have to manually create an
instance of the correct driver class. This makes switching browsers cumbersome
and error-prone.

Comparison with Interface Approach


With an interface, we can avoid these issues, as we've seen in the earlier example. Here's a
quick recap:

1. WebDriver Interface:
○ Defines common methods (get(), quit()) but leaves the implementation to
the specific browser drivers (like ChromeDriver, FirefoxDriver, etc.).
○ Makes it easy to switch between different browser implementations using
polymorphism, without altering the core test code.

2. WebDriver Class:
○ Requires modifying the class for every new browser.
○ Doesn't allow multiple inheritance and leads to tight coupling between the
test and browser-specific behavior.
○ Inflexible and harder to extend.

Conclusion

Using a class for WebDriver is less flexible compared to using an interface. The class
approach forces you to modify or subclass WebDriver for each new browser, leading to
code duplication and making it harder to maintain or extend.

By using an interface for WebDriver, Selenium allows different browser drivers to


implement their own behavior without modifying the core interface, promoting flexibility,
scalability, and maintainability across different browsers. This makes the test automation
framework more robust and easier to expand with minimal changes to the existing code.

Summary of Why WebDriver is an Interface

1. Flexibility: Allows browser-specific behavior while adhering to common rules.


2. Extensibility: Adding new browser drivers is easy without modifying existing code.
3. Polymorphism: Enables seamless switching between different browser drivers.
4. Code Reusability: Promotes clean, reusable, and maintainable code.
5. Multiple Inheritances: Allows drivers to implement WebDriver and extend other
classes.

You might also like