In the last article, we discussed the definition of a framework and expanded on it. And we tried to understand that the idea of writing your own framework isn’t quite as scary as you might think.
So today, we’re going to take the first step to creating your first framework for testing web applications in Selenium. Before we begin, I recommend reading the ‘Selenium – What is it?’ article, so you at least understand the basics of Selenium and WebDriver code.
The most important part of any Selenium based framework is that it can launch a browser, and have the flexibility to launch a variety of browsers to cover cross browser testing. And that is what our first class is going to be. Rather than do what most sites do when they go through framework tutorials, I’m going to do an article per class, but make sure that by the end of the article, you understand what’s being done, why it’s being done and my thinking behind the way I’ve done. It’s all too easy to assume that you understand code when giving examples, but if I go and put 5 classes in an article and skim across all of them, and you don’t understand any of it, how will the next article be of any help? With that said, let’s begin:
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using System;
using System.Net;
using NUnit.Framework;
namespace AutomationFramework.Engine
{
public static partial class Driver
{
public static TimeSpan TimeOut = new TimeSpan(0, 1, 0);
public static TimeSpan PollingInterval = new TimeSpan(0, 0, 2);
public static void SetImplicitTimeout(TimeSpan timeout)
{
DriverBase.Instance.Manage().Timeouts().ImplicitWait = timeout;
}
public static void SetImplicitTimeout()
{
SetImplicitTimeout(TimeOut);
}
public enum DriverType
{
InternetExplorer,
Chrome,
Edge
}
public static void Initialise(DriverType driverType, TimeSpan? implicitWait)
{
var initialiseTimeout = implicitWait ?? TimeOut;
try
{
switch (driverType)
{
case DriverType.InternetExplorer:
var internetExplorerOptions = new InternetExplorerOptions
{ IntroduceInstabilityByIgnoringProtectedModeSettings = true,
AcceptInsecureCertificates = true };
DriverBase.Instance = new InternetExplorerDriver
(TestContext.CurrentContext.TestDirectory, internetExplorerOptions));
break;
case DriverType.Edge:
var edgeExplorerOptions = new EdgeOptions { AcceptInsecureCertificates = true };
DriverBase.Instance = new EdgeDriver(TestContext.CurrentContext.TestDirectory,
edgeExplorerOptions));
break;
case DriverType.Chrome:
var chromeOptions = new ChromeOptions();
chromeOptions.AddArguments("test-type");
chromeOptions.AddArguments("chrome.switches", "--disable.extensions");
DriverBase.Instance = new ChromeDriver
(TestContext.CurrentContext.TestDirectory, chromeOptions, implicitWait);
break;
}
}
catch (WebDriverException)
{
throw new WebDriverException($"Failed to initialise the
{driverType.DescriptionAttribute()} web driver for Selenium");
}
DriverBase.Instance.Manage().Window.Maximize();
if(null != implicitWait)
{
SetImplicitTimeout((TimeSpan)implicitWait);
}
}
}
}
There are many ways to approach this, but the one we’re going to take in this example is to create our WebDriver
instance via a switch
statement that will take a parameter at another point in the framework. Depending on the parameter passed, we will create a browser specific WebDriver
instance with some options. But let’s break each bit of code down into detail.
The first thing I should cover is the fact that our class is a partial
class. The partial
keyword is used to essentially break large classes down into smaller classes across several files, purely for readability and keeping tidy code. But this is part of a bigger class that is Driver
. We’ll cover the other partial classes later on.
Once we get inside the class, we get to these few lines:
public static TimeSpan TimeOut = new TimeSpan(0, 1, 0);
public static TimeSpan PollingInterval = new TimeSpan(0, 0, 2);
public static void SetImplicitTimeout(TimeSpan timeout)
{
DriverBase.Instance.Manage().Timeouts().ImplicitWait = timeout;
}
public static void SetImplicitTimeout()
{
SetImplicitTimeout(TimeOut);
}
These are variables that we will use to set our timeout
value before our tests will give up waiting for an action to occur, and how often our framework will check for updates on an event that is possibly about to time out. There are two types of waits to keep in mind with test automation, explicit
and implicit
. Implicit
is basically telling the test to wait for a set period of time, think of a Thread.Sleep
. And an explicit
wait is telling the test to wait depending on certain conditions. Explicit
conditions are always the preferred waits to use when automated testing, purely because, the build up of implicit
waits can unnecessarily add time to your test run. It is also considered lazy to overuse implicit
waits.
After this, we create an enum
for our different Driver
types. Now this is purely a preference thing for me. You could just pass a string
in to our initialise
method, but it’s far tidier, and less error prone to just pass an enum
type in.
On to the Initialise
method:
public static void Initialise(DriverType driverType, TimeSpan? implicitWait)
{
var initialiseTimeout = implicitWait ?? TimeOut;
try
{
switch (driverType)
{
case DriverType.InternetExplorer:
var internetExplorerOptions = new InternetExplorerOptions
{ IntroduceInstabilityByIgnoringProtectedModeSettings = true,
AcceptInsecureCertificates = true };
DriverBase.Instance = new InternetExplorerDriver
(TestContext.CurrentContext.TestDirectory, internetExplorerOptions));
break;
case DriverType.Chrome:
var edgeExplorerOptions =
new EdgeOptions { AcceptInsecureCertificates = true };
DriverBase.Instance = new EdgeDriver
(TestContext.CurrentContext.TestDirectory, edgeExplorerOptions));
break;
case DriverType.Chrome:
var chromeOptions = new ChromeOptions();
chromeOptions.AddArguments("test-type");
chromeOptions.AddArguments("chrome.switches", "--disable.extensions");
DriverBase.Instance = new ChromeDriver
(TestContext.CurrentContext.TestDirectory, chromeOptions, implicitWait);
break;
}
}
catch (WebDriverException)
{
throw new WebDriverException($"Failed to initialise the
{driverType.DescriptionAttribute()} web driver for Selenium");
}
DriverBase.Instance.Manage().Window.Maximize();
if(null != implicitWait)
{
SetImplicitTimeout((TimeSpan)implicitWait);
}
}
This is where we are setting up which Driver
version we will create based on the driverType
that we pass in. It’s a simple switch
statement that will go in and set up a new instance of the driver and configure any browser specific options that we may want.
These browser settings are completely optional. And you aren’t just limited to the ones that I’m using either. There are many that can be used, and the ones you need, if any, will totally depend on the environment you’re testing on as well as any requirements set in your testing. You can read more about browser specific capabilities and what they mean here.
Once we have set our browser up and done some basic exception checking to make sure it has been properly initialised, we do a basic call to the driver instance to maximise the window. I do it here as opposed to later on, just to make sure that before we’ve even left the initialised
method, we have our browser window open and maximised.
It’s worth noting that at the moment, we are simply creating a local instance of WebDriver
, but at some point, we will look into adding remote capabilities.
That’s it for our DriverFactory
class. Simple, right? Now we need a class to wrap our WebDriver
code. In the next article, I will cover the DriverBase
class, as well as expanding on some of the other partial
classes we have in Driver
.
As a challenge, why not add Firefox driver capability and some browser options.
The post Framework – Your First Framework Part 1 appeared first on Learn Automation.