Setting Up Automation Test Screen Recorder with Selenium WebDriver and C#
As testing engineers, we often live through some bothersome scenarios. I am sure everyone can relate to the following situation: you are maintaining an automation test that keeps failing in a non-consistent way. At this moment, all you can think of is how great it would be to have some sort of test recording mechanism to help you with test issues tracking.
I’ll explain how you can easily do it on a simple C# project that will be testing this page: https://demo.nopcommerce.com/. Later, you can implement it in your testing framework and also add some cool stuff, such as video compression.
Create a Sandbox project
Open Microsoft Visual Studio and create a simple Selenium project.
NuGet packages that need to be included:
- DotNetSeleniumExtras.PageObjects
- NUnit
- NUnit3TestAdapter
- Selenium.Chrome.WebDriver
- Selenium.Firefox.WebDriver
- Selenium.Support
- Selenium.WebDriver
Project classes are defined as follows:
#Browsers.cs
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Firefox;
using System.Configuration;namespace Test
{
public class Browsers
{
public Browsers()
{
baseURL = ConfigurationManager.AppSettings["url"];
browser = ConfigurationManager.AppSettings["browser"];
}private IWebDriver webDriver;
private string baseURL;
private string browser;public void Init()
{
switch (browser)
{
case "Chrome":
webDriver = new ChromeDriver();
break;
case "Firefox":
webDriver = new FirefoxDriver();
break;
default:
webDriver = new ChromeDriver();
break;
}
webDriver.Manage().Window.Maximize();
Goto(baseURL);
}
public string Title
{
get { return webDriver.Title; }
}
public IWebDriver getDriver
{
get { return webDriver; }
}
public void Goto(string url)
{
webDriver.Url = url;
}
public void Close()
{
webDriver.Quit();
}
}
}#Pages.cs
using SeleniumExtras.PageObjects;
using System;namespace Test
{
public class Pages
{
public Pages(Browsers browser)
{
_browser = browser;
}Browsers _browser { get; }private T GetPages<T>() where T : new()
{
var page = (T)Activator.CreateInstance(typeof(T), _browser.getDriver);
PageFactory.InitElements(_browser.getDriver, page);
return page;
}
public Home Home => GetPages<Home>();
public Computers Computers => GetPages<Computers>();
}
}#Computers.cs
using NUnit.Framework;
using OpenQA.Selenium;
using SeleniumExtras.PageObjects;namespace Test
{
public class Computers
{
public Computers()
{
driver = null;
}
public Computers(IWebDriver webDriver)
{
driver = webDriver;
}//Driver
IWebDriver driver;//Locators
[FindsBy(How = How.Id, Using = "small-searchterms")]
private IWebElement SearchInput;[FindsBy(How = How.XPath, Using = "//input[@value='Search']")]
private IWebElement SearchButton;
//Actions
public Computers isAt()
{
Assert.IsTrue(driver.Title.Equals("nopCommerce demo store. Computers"));
return this;
}
public Computers EnterSearchText(string searchText)
{
SearchInput.SendKeys(searchText);
return this;
}
public Computers ClickSearch()
{
SearchButton.Click();
return this;
}
}
}#Home.cs
using NUnit.Framework;
using OpenQA.Selenium;
using SeleniumExtras.PageObjects;namespace Test
{
public class Home
{
public Home()
{
driver = null;
}
public Home(IWebDriver webDriver)
{
driver = webDriver;
}//Driver
IWebDriver driver;//Locators
[FindsBy(How = How.XPath, Using = "//ul[@class='top-menu notmobile']//a[@href='/computers']")]
private IWebElement ComputersLink;//Actions
public Home isAt()
{
Assert.IsTrue(driver.Title.Equals("nopCommerce demo store"));
return this;
}
public Home GoToComputers()
{
ComputersLink.Click();
return this;
}
}
}#MyFirstTest.cs
using NUnit.Framework;namespace Test
{
[TestFixture]
public class MyFirstTest : TestBase
{
[Test]
public void NopCommerceDummyTest()
{
Pages.Home.isAt();
Pages.Home.GoToComputers();
Pages.Computers.isAt();
Pages.Computers.EnterSearchText("Search me!");
Pages.Computers.ClickSearch();
}
}
}#TestBase.cs
using NUnit.Framework;namespace Test
{
[TestFixture]
public abstract class TestBase
{
protected Browsers browser;
protected Pages Pages;[SetUp]
public void StartUpTest()
{
browser = new Browsers();
browser.Init();
Pages = new Pages(browser);
}[TearDown]
public void EndTest()
{
browser.Close();
}
}
}
The simple framework is created as a TDD framework with its data stored in App.config file.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="url" value="https://demo.nopcommerce.com" />
<add key="browser" value="Firefox" />
</appSettings>
</configuration>
If we run the test, it will pass within 10 seconds.
Let’s begin with the TestRecorder implementation.
Navigate to this Microsoft page https://www.microsoft.com/en-us/download/details.aspx?id=27870, then download and install the Microsoft Expression Encoder 4 with Service Pack 2 (SP2) tool on a testing machine — in my case, that’s my host machine.
Open NuGet Package Manager, search for Microsoft.Expression.Encoder and install it to your project.
Since recordings take up a lot of space, let’s create a configuration where we’ll define for how many days we’ll keep the video recordings on our hard/solid-state drive.
Add a new App.config node:
<add key="recordingHistory" value="1" />
Value = 1 tells us that we’ll keep video files for a day.
Your configuration file should now look like this:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="url" value="https://demo.nopcommerce.com" />
<add key="browser" value="Firefox" />
<add key="recordingHistory" value="1" />
</appSettings>
</configuration>
I’m now going to add a new Folder RecordingHelper and class ScreenRecorder.cs that will be handling screen recordings.
ScreenRecorder.cs:
using Microsoft.Expression.Encoder.ScreenCapture;
using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Reflection;namespace Test
{
public class ScreenRecorder
{
private ScreenCaptureJob screenCaptureJob = new ScreenCaptureJob();
private readonly string OutputDirectoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);public void SetVideoOutputLocation(string testName = "")
{
if (string.IsNullOrEmpty(testName))
testName = "AutomationTest";
screenCaptureJob.OutputScreenCaptureFileName = Path.Combine(OutputDirectoryName, string.Format("{0}{1}.avi", testName, DateTime.UtcNow.ToString("MMddyyyy_Hmm")));
}private void DeleteOldRecordings()
{
int daysCount = Convert.ToInt16(ConfigurationManager.AppSettings["recordingHistory"]);Directory.GetFiles(OutputDirectoryName)
.Select(f => new FileInfo(f))
.Where(f => (f.LastAccessTime < DateTime.Now.AddDays(-daysCount)) && (f.FullName.Contains(".avi")))
.ToList()
.ForEach(f => f.Delete());
}public void StartRecording()
{
DeleteOldRecordings();
screenCaptureJob.Start();
}public void StopRecording()
{
screenCaptureJob.Stop();
}
}
}
- SetVideoOutputLocation() method sets the video output location. I’m using project output folder:
- StartRecording() method will delete all old recordings by the rule set in the application configuration file, and then start recording. The best option is to call the method in the set-up part of a test.
- StopRecording() method will stop recording process and save a file to the location set using SetVideoOutputLocation() method. We’ll call it in test tear down method.
Now let’s put everything to the TestBase.cs:
using NUnit.Framework;
using NUnit.Framework.Interfaces;
using OpenQA.Selenium;
using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Reflection;namespace Test
{
[TestFixture]
public abstract class TestBase
{
protected ScreenRecorder sr = new ScreenRecorder();
protected Browsers browser;
protected Pages Pages;[SetUp]
public void StartUpTest()
{
browser = new Browsers();
browser.Init();
Pages = new Pages(browser);
sr.SetVideoOutputLocation();
sr.StartRecording();
}[TearDown]
public void EndTest()
{
if (TestContext.CurrentContext.Result.Outcome != ResultState.Success)
{
int daysCount = Convert.ToInt16(ConfigurationManager.AppSettings["recordingHistory"]);
string OutputDirectoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);Directory.GetFiles(OutputDirectoryName)
.Select(f => new FileInfo(f))
.Where(f => (f.LastAccessTime < DateTime.Now.AddDays(-daysCount)) && (f.FullName.Contains(".png")))
.ToList()
.ForEach(f => f.Delete());var screenshot = ((ITakesScreenshot)browser.getDriver).GetScreenshot();
screenshot.SaveAsFile(Path.Combine(OutputDirectoryName, string.Format("FAILED_Test_{0}.png", DateTime.UtcNow.ToString("MMddyyyy_Hmm"))));
}
browser.Close();
sr.StopRecording();
}
}
}
Besides video capturing, we are also taking a screenshot on test exception in order to store the moment of failure.
Run the test and navigate to the output folder once the testing is done. You will find an avi file there. Png file will be there only if your test failed. Run the video to see what’s been recorded. If you were interacting with the computer while the test was running, that will be recorded too.
I hope this tutorial helps you tackle one of the many challenges we encounter on a daily basis. Till the next time, Happy Testing!