Why Selenium WebDriver is an Interface
Why Selenium WebDriver is 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.
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:
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();
}
// Usage
public class TaxiService {
public static void main(String[] args) {
Taxi toyotaTaxi = new Toyota();
toyotaTaxi.startCar();
toyotaTaxi.driveToLocation("Airport");
toyotaTaxi.stopCar();
System.out.println();
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.
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;
driver.get("https://example.com");
System.out.println("Title: " + driver.getTitle());
driver.quit();
}
}
With an Interface:
You reuse the same code for all browser drivers, making maintenance easier.
Example:
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:
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:
Example:
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.");
}
}
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.
4. Code Reusability
Using an Interface:
interface WebDriver {
void get(String url);
void quit();
}
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.
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:
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:
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:
Output:
Opening https://google.com in Chrome.
Closing Chrome browser.
Opening https://google.com in Firefox.
Closing Firefox browser.
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.
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.