Skip to content

The Real Selenium Hierarchy

SearchContext, WebDriver, RemoteWebDriver, and ChromeDriver are ordinary Java — two interfaces and two classes. Reading that hierarchy answers 'why is WebDriver an interface?' for good.

2 min read

You can now read Selenium's own design as ordinary Java. SearchContext is the topmost interface, declaring only findElement and findElements. WebDriver is an interface that extends it, adding the browser-level methods such as get, close, and quit. RemoteWebDriver is a class that implements those interfaces, supplying real bodies for every one of those methods. And ChromeDriver, FirefoxDriver, and EdgeDriver extend RemoteWebDriver.

So the famous line contains everything in this chapter and the last. WebDriver is an interface used as the declared type. ChromeDriver is a class several levels down that ultimately satisfies that contract. The assignment is an upcast, and every method call on driver is resolved at run time against the real object.

Write it the other way — ChromeDriver driver = new ChromeDriver(); — and it still compiles and still runs. But now every method that receives that variable is tied to Chrome, and switching browsers means editing code rather than changing a configuration value. The interface on the left is what makes the suite portable.

Where declaring the concrete type actually costs you

A framework declares ChromeDriver driver = new ChromeDriver(); in BaseTest, and a helper method takes a ChromeDriver parameter. It runs correctly, and declaring the real type is honest — you get Chrome-specific methods without casting, and today the suite only tests on Chrome. The problem shows up the day a client asks for Edge: the change is not one line in a config file, it is every signature that mentions ChromeDriver. That is a day of work, once — plus a regression risk across the whole suite, to avoid typing one word today. And it costs the ability to run the same suite on a remote grid, where the object is a RemoteWebDriver rather than a ChromeDriver. Declare the interface, create the implementation. WebDriver driver = new ChromeDriver(); costs nothing today and keeps every future option open. Reach for the concrete type only when you genuinely need a method the interface does not offer, and confine that to one place.

Interfaces are the joints a framework bends at. WebDriver lets one suite drive any browser. WebElement is an interface, which is why the same code handles a button and a text field. A DriverFactory returns a WebDriver, hiding which browser was built. Page Objects are usually classes extending an abstract BasePage, because they share real state — the driver — while capability contracts such as Reportable or Retryable are interfaces. When you write a helper, take the interface as the parameter type: a method that accepts WebDriver works with everything, and a method that accepts ChromeDriver works with one thing.

Every idea in this chapter compounds into that one hierarchy. The closing bug hunt shows exactly how easy it is to write code that quietly throws all of it away.

This article is part of Automation Foundations, in the Automation Engineering track. See the full sequence to find what comes next.