WebDriver Factory

One of the many benefits of WebDriver is that the major browsers are all supported with a version of a driver, some within the browsers and others via a service. This means that you should be able to run your suites of tests against these browsers. This is true, unfortunately though some browsers behave differently so you're likely to face some locators discrepancies, but that's for another post!

So how can you write a framework allowing you to take advantage of these drivers, they're many approaches, it's code at the end of the day, but I use the approach I call the DriverFactory, as do a few others I have seen, such as an example here by Jim Evans.

The concept is very simple, I have attached a diagram below, but here is the jist:

  • App.config file where we define our browser requirements
  • TestConfiguration object which is static, therefore reads the App.config at runtime and creates an instance for us to use throughout the tests. In the example project below I only have driver specific values, however in actual projects I also include any test config in there, e.g. username, passwords, DB connections etc.
  • DriverSetup this is specific to NUnit, but I use the SetUpFixture to deal with the requesting of a driver instead of doing this in each test. Because the namespace on this class is the highest, each test will call this code first before its own SetUp.
  • TestDriverFactory, this is where we interpret the TestConfiguration object to determine which DriverFactory configuation we require. This is decided based on the "Remote" value, if true we create a RemoteWebDriverConfig, if false a LocalWebDriverConfig.
    The TestDriverFactory will then pass those configs to the DriverFactory and expect a driver back that meets the requirements.
  • DriverFactory, this is where the required driver is created. It's a simple switch statement on the browser name.

An example project can be viewed here on my GitHub page and click WebDriverFactoryExample. I have added extensive code comments so hopefully all can follow. Also have an example PageObject and Test so you can see it all together. Changing the browser name to those in the switch statement will work fine, remember if you are going to try it with RemoteWebDriver ensure to have it running and the correct browser versions registered on the nodes.

NOTE: To really take advantage of all the browsers, ensure to use the interface IWebDriver throughout your tests and PageObjects, as all drivers are contracted to this interface you won't have any issues with different browsers. For instance not all drivers (haven't checked recently) have the driver.FindElementBySomething, so if you've written your tests with a specific driver and not IWebDriver your tests could fail when using drivers that don't have such a method. So stick to the FindsBy attribute and if you have to use the driver directly ensure to use driver.FindElement(By.Something) or FindElements.

So what you have now is the ability to control the driver used to run the test suite via config. This allows you take advantage of CI tools such as Jenkins to run your tests potentially in parallel against multiple browsers. Via a CI you could have a main Job, "Run Test Suite" which could trigger down stream jobs of "Run Test Suite - IE", "Run Test Suite - Chrome" and so forth by having those downstream jobs overwrite the app.config before the test run. Or you could have multiple config files in your solution, such as chrome.config, ie.config etc and have your CI tools delete app.config and rename the required driver.config to app.config (this is required for NUnit) thus allowing you to have the configs in source control and not in build jobs.

In my example I have the WebDriverFactory as a separate project, but to take this one step further, you could turn the separate project into a NuGet package (you would obviously need an internal NuGet server to do this), this will then allow you to add this package to any project where you require WebDriver, for example if you had multiple products, or multiple test suites for a product.

In doing this, if you execute your tests locally, you can store the additional driver services in this project and have them pulled into projects via NuGet. These would be InternetExplorerDriver, ChromeDriver and PhantomJS for example. It would then be possible to have your CI download the latest version of this package for you, making it very easy to update all your projects.

Thanks to Neil Kilbride and James Barker from Esendex for showing me the NuGet approach and the enhancements for dealing with local and remote config objects.