Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / WebDriver

WebDriverManager Fabric Example for Selenium Based Frameworks

0.00/5 (No votes)
22 Jun 2017CPOL3 min read 8.9K  
The most known and possible solution for such cases is creating a custom WebDriver manager based on the Factory design pattern. There are lots of different implementations on GitHub and you can easily Google them, but today, I want to share one of the latest experiments that I did.

I guess most people who are involved in the automated testing of web applications to some extent, came up to the managing of browsers and their drivers while working with Selenium-based test frameworks. There might be a lot of solutions how to make their life easier. Some out-of-the-box frameworks (like Selenide) have already implemented WebDriver managers internally, however, in some cases, we need to handle it by ourselves.

The most known and possible solution for such cases is creating a custom WebDriver manager based on the Factory design pattern. There are lots of different implementations on GitHub and you can easily Google them, but today I’d want to share one of the latest experiments that I did (inspired by this solution with enums). So, here we go…

Challenge: To implement a Browser Manager (i.e., WebDriver manager) which simplifies running tests on different browsers, including parallel execution.

First of all, let’s get rid of annoying drivers binaries management! As you know, each browser has its own driver binary which should be downloaded and its location should be added to the classpath. The WebDriverManager project provides the API for downloading necessary drivers and configuring system properties automatically. All you need is love to add its dependency (through Maven or Gradle) and call a fabric method relevant to a needed browser:

C#
ChromeDriverManager.getInstance().setup();

// Then you can create a new driver in a usual way:
driver = new ChromeDriver();

It’s pretty easy, isn’t it? It supports Firefox, Chrome, Opera, Internet Explorer, Edge and PhantomJS browsers for now, but I’m going to add the HtmlUnit browser in the final solution also. The WebDriverManager mentioned above allows us to also specify architecture, driver version and several other parameters if necessary).

Following the code above and using the example for enums, let’s create our own Browser enum with all browsers listed above:

C#
public enum Browser {

    FIREFOX {
        @Override
        public WebDriver initialize(DesiredCapabilities capabilities) {
            synchronized (BrowserManager.class) {
                FirefoxDriverManager.getInstance().setup();
                return new FirefoxDriver(capabilities);
            }
        }
    },

    CHROME {
        @Override
        public WebDriver initialize(DesiredCapabilities capabilities) {
            synchronized (BrowserManager.class) {
                ChromeDriverManager.getInstance().setup();
                return new ChromeDriver(capabilities);
            }
        }
    },

    IE {
        // similar logic for InternetExplorer
    },

    EDGE {
        // similar logic for Edge
    },

    OPERA {
        // similar logic for Opera
    },

    PHANTOMJS {
        // similar logic for PantomJS
    },

    HTMLUNIT {
        @Override
        public WebDriver initialize(DesiredCapabilities capabilities) {
            return new HtmlUnitDriver(capabilities);
        }
    };

    public abstract WebDriver initialize(DesiredCapabilities capabilities);

    }
}

The logic of the whole enum is incredibly simple: there is the abstract initialize() method which must be implemented for each member of the enum. Each overridden initialize() method (excepts for the HtmlUnit driver) sets up an instance of a required driver manager class and then returns a required driver after all dependencies are downloaded and configured. In order to make the WebDriverManager API more thread-safe while running tests in different browsers in parallel, I also put all code related to the BrowserManager.class inside the synchronized {..} block.

The final step before moving forward to the fabric usage in the framework is to create the fabric. Let’s make the new BrowserProvider class:

C#
public class BrowserProvider {

    public static WebDriver createDriver(Browser browser, DesiredCapabilities capabilities) {
        capabilities.setBrowserName(browser.toString().toLowerCase());
        return browser.initialize(capabilities);
    }

    public static WebDriver createDriver(Browser browser) {
        return createDriver(browser, new DesiredCapabilities());
    }

    public static RemoteWebDriver createDriver
        (URL hubUrl, Browser browser, DesiredCapabilities capabilities) {
        capabilities.setBrowserName(browser.toString().toLowerCase());
        return new RemoteWebDriver(hubUrl, capabilities);
    }

    public static RemoteWebDriver createDriver(URL hubUrl, Browser browser) {
        return createDriver(hubUrl, browser, new DesiredCapabilities());
    }
}

There are two methods for the RemoteWebDriver creation and two similar ones for the local test tun. All of them take a Browser as a parameter which can be passed from a test (or any other setup class that you may use). Optionally, methods can take DesiredCapabilities.

Now we can use the fabric from the test code:

C#
public class LocalTestsExample {

    private WebDriver driver;

    @BeforeClass
    @Parameters("browser")
    public void setUpClass(Browser browser) {
        driver = BrowserProvider.createDriver(browser);
    }

    @Test
    public void CodeIconLoadingTest() { }

    @AfterClass
    public void tearDownTest() { }    
}

As you have noticed, I used TestNG annotations inside the test code. It’s because I prefer this test framework from the easy parametrization point of view, so it’s suitable for demonstrating a parallel test execution in different browsers. Here is how the typical TestNG file may look like:

XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">

<suite name="TestSuite" parallel="tests">
    <test name="EdgeTest">
        <parameter name="browser" value="EDGE" />
            <classes>
                <class name="LocalTestsExample"/>
            </classes>
    </test>
    <test name="FirefoxTest">
        <parameter name="browser" value="FIREFOX" />
            <classes>
                <class name="LocalTestsExample"/>
            </classes>
    </test>
</suite>

When you run your test through the above-mentioned TestNG file, you’ll see Firefox and Edge browsers starting and running tests in parallel. You can easily add any other of the supported browsers and run them in parallel as well as separately. Please note that the very first run for each browser might take more time – WebDriverManager will download necessary binaries to the local Maven repository.

The complete project code is available on GitHub, so feel free to add it to your project, use and / or modify according to your needs, if necessary. Any suggestions are welcome!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)