Selenium Test Automation Framework using NUnit and C# | Code Example

Today I will focus to develop a Selenium Test Automation Framework using NUnit and C#. The Framework going to have 4 mandatory folder “Bases, Pages, Steps and Tests” for implement Page Object Model and 2 additional folder “Hooks and Test Data”. Actually Page Object Model concept give a SDET more independence to Repair, Maintain and Update the Framework whenever need.

Bases:

Base is for keeping common items which you are going to use in framework many times. Simple Base classes are as below,

  • TestBase.cs
using System;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

namespace MyNamespace
{
    [TestFixture]
    public class BaseFramework
    {
        protected IWebDriver driver = null;

        [SetUp]
        public void Initialize()
        {
            driver = new ChromeDriver();
            driver.Manage().Window.Maximize();
            Console.WriteLine("Using Nunit SetUp to Open Browser with Selenium Webdriver");

        }

        [TearDown]
        public void CleanUpBrowser()
        {
            driver.Quit();
            Console.WriteLine("Using Nunit TearDown to CleanUp Browser");
        }


        public StepsOne ControllerOne()
        {
            return new StepsOne(driver);
        }

        public StepsTwo ControllerTwo()
        {
            return new StepsTwo(driver);
        }

        public StepsThree ControllerThree()
        {
            return new StepsThree(driver);
        }

        public DataModel TestData()
        {
            return new DataModel(driver);
        }
    }
}
  • PageBase.cs
using OpenQA.Selenium;

namespace MyNamespace
{
    public class BasePage
    {
        protected IWebDriver driver; 

        public BasePage(IWebDriver driver)
        {
            this.driver = driver;
        }
    }
}
  • StepBase.cs
using OpenQA.Selenium;

namespace MyNamespace
{
    public class BaseStep
    {
        protected IWebDriver driver;

        public BaseStep (IWebDriver driver)
        {
            this.driver = driver;
        }
    }
}
  • TestDataBase.cs
using OpenQA.Selenium;

namespace MyNamespace
{
    public class BaseTestData
    {
        protected IWebDriver driver;

        public BaseTestData(IWebDriver driver)
        {
            this.driver = driver;
        }
    }
}
  • HookBase.cs
using OpenQA.Selenium;

namespace MyNamespace
{
    public class BaseHook
    {
          protected IWebDriver driver;
          public BaseHook(IWebDriver driver)
          {
          this.driver = driver;
          }

        public IWebDriver driver { get; set; }
    }
}

Pages

Pages folder usually contain Classes for Page Objects of a particular page which going to used by selenium web-driver.

  • PageOneObjects.cs
using OpenQA.Selenium;
using OpenQA.Selenium.Support.PageObjects;

namespace MyNamespace
{
    public class PageOne : BasePage
    {

        public PageOne(IWebDriver driver) : base(driver)
        {
        }

        protected IWebElement UserName = null;
        protected IWebElement Password = null;
        protected IWebElement Login = null;
        protected IWebElement SearchBy = null;
        protected IWebElement Option = null;

        public IWebElement TxtUserName()
        {
            UserName = driver.FindElement(By.XPath("//*[@id='myUname']"));
            return UserName;
        }

        public IWebElement TxtPassword()
        {
            Password = driver.FindElement(By.XPath("//*[@id='myUpass']"));
            return Password;
        }

        public IWebElement BtnNext()
        {
            Login = driver.FindElement(By.XPath("//*[@id='btnNext']"));
            return Login;
        }

        public IWebElement DDSearchBy()
        {
            SearchBy = driver.FindElement(By.XPath("//*[@id='btnNext']"));
            return SearchBy;
        }

        public IWebElement Option1()
        {
            Option = driver.FindElement(By.XPath("//*[@id='btnNext']"));
            return Option;
        }

        [FindsBy(How = How.XPath, Using = ".//*[@id='sampleId']/tbody")]
        public IWebElement SamplePageFactory { get; set; }

    }
}
  • PageTwoObjects.cs
using OpenQA.Selenium;

namespace MyNamespace
{
    public class PageTwo : BasePage
    {
        public PageTwo(IWebDriver driver) : base(driver)
        {
        }

        protected IWebElement PGobj1 = null;
        protected IWebElement PGobj2 = null;
        protected IWebElement PGobj3 = null;

        public IWebElement DDPGobj1()
        {
            PGobj1 = driver.FindElement(By.XPath("//*[@id='Sampleid1']"));
            return PGobj1;
        }

        public IWebElement TxtPGobj2()
        {
            PGobj2 = driver.FindElement(By.XPath("//*[@id='Sampleid2']"));
            return PGobj2;
        }

        public IWebElement BtnPGobj3()
        {
            PGobj3 = driver.FindElement(By.XPath("//*[@id='Sampleid3']"));
            return PGobj3;
        }
    }
}
  • PageThreeObjects.cs
using OpenQA.Selenium;

namespace MyNamespace
{
    public class PageThree : BasePage
    {
        public PageThree(IWebDriver driver) : base(driver)
        {
        }

        protected IWebElement SamplePageObject = null;

        public IWebElement BtnPageObject()
        {
            SamplePageObject = driver.FindElement(By.XPath("//*[@id=myId"));
            return SamplePageObject;
        }
    }
}

Steps

Steps folder usually contains classes for reusable functional library of particular page.

  • PageOneSteps.cs
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using System.Linq;
using System.Threading;
using System;

namespace MyNamespace
{
    public class StepsOne : BaseStep
    {
        public PageOne PageOneModel = null;

        public StepsOne(IWebDriver driver) : base(driver)
        {
            PageOneModel = new PageOne(driver);
        }

        public void FunctionNavigateURL(string Url)
        {
            driver.Navigate().GoToUrl(Url);
        }
        public void FunctionSimple (string UserName, string Password)
        {
            PageOneModel.TxtUserName().Clear();
            PageOneModel.TxtUserName().SendKeys(UserName);
            PageOneModel.TxtPassword().Clear();
            PageOneModel.TxtPassword().SendKeys(Password);
            PageOneModel.BtnNext().Click();
        }

        internal void FunctionAssert(int v)
        {
            throw new NotImplementedException();
        }

        public void FunctionDropDown(string SearchBy)
        {
            SelectElement mydrpdwn = new SelectElement(PageOneModel.DDSearchBy());
            mydrpdwn.SelectByText(SearchBy);
        }

        public void FunctionSwitchWindow(string URL1)
        {
            driver.SwitchTo().Window(driver.WindowHandles.Last());
            Assert.AreEqual(URL1, driver.Url);
            driver.Close();
            driver.SwitchTo().Window(driver.WindowHandles.First());
        }

        public void FunctionAssert(string Submit)
        {
            Assert.IsTrue((PageOneModel.BtnNext()).Text.Contains(Submit));
        }

        public void FunctionWait(int time)
        {
            Thread.Sleep(time);
        }
        public void FunctionAlertAccept()
        {
            IAlert Aleart = driver.SwitchTo().Alert();
            Aleart.Accept();
        }
    }
}
  • PageTwoSteps.cs
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;

namespace MyNamespace
{
    public class StepsTwo : BaseStep
    {
        public PageTwo PageTwoModel = null;

        public StepsTwo(IWebDriver driver) : base(driver)
        {
            PageTwoModel = new PageTwo(driver);
        }

        public void FunctionDrpDwn (string SearchBy, string Value)
        {
            SelectElement mydrpdwn = new SelectElement(PageTwoModel.DDPGobj1());
            mydrpdwn.SelectByText(SearchBy);
            PageTwoModel.TxtPGobj2().Clear();
            PageTwoModel.TxtPGobj2().SendKeys(Value);
            PageTwoModel.BtnPGobj3().Click();
        }
    }
}
  • PageThreeSteps.cs
using OpenQA.Selenium;

namespace MyNamespace
{
    public class StepsThree : BaseStep
    {
        public PageThree PageThreeModel = null;

        public StepsThree(IWebDriver driver) : base(driver)
        {
            PageThreeModel = new PageThree(driver);
        }

        public void FunctionLibrary ()
        {
            PageThreeModel.BtnPageObject().Click();
        }
    }
}

Tests

Tests folder contain classes with test

  • RegressionTest.cs
using NUnit.Framework;

namespace MyNamespace
{
    [TestFixture]
    public class RegressionTest : BaseFramework
    {
        //string Url;

        [Test]
        public void SampleTest()
        {
            ControllerOne().FunctionNavigateURL(TestData().Url());
            ControllerOne().FunctionSimple(TestData().UserName(), TestData().UserPass());
            ControllerOne().FunctionDropDown(TestData().SearchBy());
            ControllerOne().FunctionSwitchWindow(TestData().OtherURL());
            ControllerOne().FunctionAssert(TestData().Text());
            ControllerOne().FunctionWait(TestData().TimeSec());
            ControllerOne().FunctionAlertAccept();
            ControllerTwo().FunctionDrpDwn(TestData().Search(), TestData().Value());
            ControllerThree().FunctionLibrary();
        }

        [Test]
        public void SampleTest2()
        {
            ControllerOne().FunctionNavigateURL(TestData().Url());
            ControllerOne().FunctionSimple(TestData().UserName(), TestData().UserPass());
            ControllerOne().FunctionDropDown(TestData().SearchBy());
            ControllerOne().FunctionSwitchWindow(TestData().OtherURL());
            ControllerOne().FunctionAssert(TestData().Text());
            ControllerOne().FunctionWait(TestData().TimeSec());
        }

        [Test]
        public void SampleTest3()
        {
            ControllerOne().FunctionAssert(TestData().Text());
            ControllerOne().FunctionWait(TestData().TimeSec());
            ControllerOne().FunctionAlertAccept();
            ControllerTwo().FunctionDrpDwn(TestData().Search(), TestData().Value());
            ControllerThree().FunctionLibrary();
        }

    }
}
  • ParallelTest.cs
using NUnit.Framework;

namespace MyNamespace
{
    [TestFixture]
    [Parallelizable]
    public class ParallelTestChrome : ParallelTestHook
    {

        public ParallelTestChrome() : base(BrowserType.Chrome)
        {
        }

        [Test]
        public void ParallelTestChromeW1()
        {  
            driver.Navigate().GoToUrl("http://myurl.com");
            driver.Manage().Window.Maximize();
        }
    }

    [TestFixture]
    [Parallelizable]
    public class ParallelTestChrome2 : ParallelTestHook
    {
        public ParallelTestChrome2() : base(BrowserType.Chrome)
        {
        }

        [Test]
        public void ParallelTestChromeW2()
        {
            driver.Navigate().GoToUrl("http://myurl.com");
            driver.Manage().Window.Maximize();
        }
    }

    [TestFixture]
    [Parallelizable]
    public class ParallelTestFirefox : ParallelTestHook
    {
        public ParallelTestFirefox() : base(BrowserType.Firefox)
        {
        }

        [Test]
        public void ParallelTestFirefoxW3()
        {
            driver.Navigate().GoToUrl("http://myurl.com");
            driver.Manage().Window.Maximize();
        }
    }

    [TestFixture]
    [Parallelizable]
    public class ParallelTestFirefox2 : ParallelTestHook
    {
        public ParallelTestFirefox2() : base(BrowserType.Firefox)
        {
        }

        [Test]
        public void ParallelTestFirefoxW4()
        {
            driver.Navigate().GoToUrl("http://myurl.com");
            driver.Manage().Window.Maximize();
        }
    }
}

Test Data

Test Data folder contains classes and xml file which has test data sets for different test suite. It also known as Data Model or DM which is very popular and useful.

  • DataModel.cs
using System.Xml;
using OpenQA.Selenium;
using System.Configuration;

namespace MyNamespace
{ 
    public class DataModel : BaseTestData
    {
        public DataModel(IWebDriver driver) : base(driver)
        {
        }

        public string Url()
        {
            XmlDocument myXml = new XmlDocument();
            myXml.Load(ConfigurationManager.AppSettings["DataFilePath"]);
            return (myXml.GetElementsByTagName("Url"))[0].InnerText;
        }

        public string UserName()
        {
            XmlDocument myXml = new XmlDocument();
            myXml.Load(ConfigurationManager.AppSettings["DataFilePath"]);
            return (myXml.GetElementsByTagName("UserName"))[0].InnerText;
        }

        public string UserPass()
        {
            XmlDocument myXml = new XmlDocument();
            myXml.Load(ConfigurationManager.AppSettings["DataFilePath"]);
            return (myXml.GetElementsByTagName("UserPass"))[0].InnerText;
        }

        public string SearchBy()
        {
            XmlDocument myXml = new XmlDocument();
            myXml.Load(ConfigurationManager.AppSettings["DataFilePath"]);
            return (myXml.GetElementsByTagName("SearchBy"))[0].InnerText;
        }

        public string OtherURL()
        {
            XmlDocument myXml = new XmlDocument();
            myXml.Load(ConfigurationManager.AppSettings["DataFilePath"]);
            return (myXml.GetElementsByTagName("OtherURL"))[0].InnerText;
        }

        public string Text()
        {
            XmlDocument myXml = new XmlDocument();
            myXml.Load(ConfigurationManager.AppSettings["DataFilePath"]);
            return (myXml.GetElementsByTagName("Text"))[0].InnerText;
        }

        public int TimeSec()
        {
            XmlDocument myXml = new XmlDocument();
            myXml.Load(ConfigurationManager.AppSettings["DataFilePath"]);
            return int.Parse((myXml.GetElementsByTagName("TimeSec"))[0].InnerText);
        }

        public string Search()
        {
            XmlDocument myXml = new XmlDocument();
            myXml.Load(ConfigurationManager.AppSettings["DataFilePath"]);
            return (myXml.GetElementsByTagName("Search"))[0].InnerText; ;
        }

        public string Value()
        {
            XmlDocument myXml = new XmlDocument();
            myXml.Load(ConfigurationManager.AppSettings["DataFilePath"]);
            return (myXml.GetElementsByTagName("Value"))[0].InnerText; ;
        }
    }
}
  • TestData.xml

Xml.jpg

Hooks

Hooks folder contain classes to hook different activities with framework, as example class for handling complex tables object, parallel test, using Excel file for test data etc.

  • ComplexTable.cs
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.PageObjects;
using OpenQA.Selenium.Support.UI;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace MyNamespace
{

    public class ComplexTable : Base
    {
        [Test]
        public void ComplexTableCheck()
        {
            driver = new FirefoxDriver();
            driver.Navigate().GoToUrl("https://myurl/url.aspx");

            TablePage page = new TablePage();

            //read table
            Utilties.ReadTable(page.table);

            Console.WriteLine("**********************************");
            //Get the cell value from the table
            Console.WriteLine("The name {0} with Email {1} and Phone {2}",
                Utilties.ReadCell("Name", 2), Utilties.ReadCell("Email", 2), Utilties.ReadCell("Phone", 2));
            Console.WriteLine("**********************************");

            //Delete Prashanth
            Utilties.PerformActionOnCell("5", "Name", "Prashanth", "Delete");
            //Save Prashanth
            Utilties.PerformActionOnCell("5", "Name", "Prashanth", "Save");
            //Checkbox Prashanth
            Utilties.PerformActionOnCell("Option", "Name", "Prashanth");

            Console.Read();
        }

        [Test]
        public void ComplexTableTest()
        {
            driver = new ChromeDriver();
            driver.Manage().Window.Maximize();
            driver.Navigate().GoToUrl("https://myUrl/url.aspx");
            Console.WriteLine("Using Nunit SetUp to Open Browser with Selenium Webdriver");
            SelectElement mydrpdwn = new SelectElement(driver.FindElement(By.XPath("//*[@id='ddlSample']")));
            mydrpdwn.SelectByText("sampleText");
            driver.FindElement(By.XPath("//*[@id='Value1']")).SendKeys("sampleString");
            driver.FindElement(By.XPath("//*[@id='test']")).Click();
            driver.FindElement(By.XPath("//*[@id='ComplexTable']/tbody/tr[22]/td[45]/a")).Click();
            driver.Close();
            driver.SwitchTo().Window(driver.WindowHandles.Last());
            driver.FindElement(By.XPath(".//a[contains(@href,'fh123')]/img[contains(@src,'../images/pid.png')]")).Click();
            TablePage page = new TablePage();
            Utilties.ReadTable(page.table);
            Utilties.PerformActionOnCell("StringValue1", "StringValue2", "StringValue3");
        }
    }



    public class TablePage : Base
    {
        public TablePage()
        {
            PageFactory.InitElements(driver, this);
        }

        [FindsBy(How = How.XPath, Using = ".//*[@id='sampleId']/tbody")]
        public IWebElement table { get; set;}
    }



    public class Base
    {
        public static IWebDriver driver;
    }



    public class TableDataCollection
    {
        public int RowNumber { get; set; }
        public string ColumnName { get; set; }
        public string ColumnValue { get; set; }
        public IEnumerable ColumnSpecialValues { get; set; }
    }



    public class Utilties
    {
        static List _tableDatacollections = new List();

        public static void ReadTable(IWebElement table)
        {
            //Get all the Column from the table
            var columns = table.FindElements(By.TagName("td"));
            //Get all the raws from the table
            var rows = table.FindElements(By.TagName("tr"));
            //Create row index
            int rowIndex = 0;

            foreach (var row in rows)
            {
                int colIndex = 0;
                var colDates = row.FindElements(By.TagName("td"));
                foreach (var colValue in colDates)
                {
                    _tableDatacollections.Add(new TableDataCollection
                    {
                        RowNumber = rowIndex,
                        ColumnName = columns[colIndex].Text != "" ?
                                    columns[colIndex].Text : colIndex.ToString(),
                        ColumnValue = colValue.Text,
                        ColumnSpecialValues = colValue.Text != "" ? null :
                                              colValue.FindElements(By.TagName("img"))
                    });

                    //move to next column
                    colIndex++;
                }
                rowIndex++;
            }
        }

        public static string ReadCell(string columnName, int rowNumber) 
        {
            var data = (from e in _tableDatacollections
                        where e.ColumnName == columnName && e.RowNumber == rowNumber
                        select e.ColumnValue).SingleOrDefault();

            return data;
        }

        public static void PerformActionOnCell(string columnIndex, string refColumnName, string refColumnValue, string controlToOperate = null)
        {
            foreach (int rowNumber in GetDynamicRowNumber(refColumnName, refColumnValue))
            {
                var cell = (from e in _tableDatacollections
                            where e.ColumnName == columnIndex && e.RowNumber == rowNumber
                            select e.ColumnSpecialValues).SingleOrDefault();


                //Need to operate those controls
                if (controlToOperate != null && cell !=null)
                {
                    var returnedControl = (from c in cell
                                          where c.GetAttribute("src") == controlToOperate 
                                          select c).SingleOrDefault();
                    returnedControl?.Click();
                }
                else
                {
                    cell?.First().Click();
                }
             }
        }

        private static IEnumerable GetDynamicRowNumber(string columnName, string columnValue)
        {
            //dynamic row 
            foreach (var table in _tableDatacollections)
            {
                if (table.ColumnName == columnName && table.ColumnValue == columnValue)
                    yield return table.RowNumber;
            }
        }

    }
}
  • ParallelTestHook.cs
using NUnit.Framework;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Firefox;

namespace MyNamespace
{
    public enum BrowserType
    {
        Chrome,
        Firefox,
        IE
    }

    [TestFixture]
    public class ParallelTestHook : BaseHook
    {
        private BrowserType _browserType;

        public ParallelTestHook(BrowserType browser)
        {
            _browserType = browser;
        }

        [SetUp]
        public void InitializeTest()
        {
            ChooseDriverInstance(_browserType);
        }

        private void ChooseDriverInstance(BrowserType browserType)
        {
            if (browserType == BrowserType.Chrome)
                driver = new ChromeDriver();
            else if (browserType == BrowserType.Firefox)
                driver = new FirefoxDriver();
        }
    }
}
  • ExcelLibrary.cs
using Excel;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;

namespace MyNamespace
{
    class ExcelLibrary
    {
        [Test]
        public void Samplelogin()
        {
        ExcelLibrary.PopulateInCollection(@"E:\Directory\xlName.xlsx");
        //Page.login(ExcelLibrary.ReadData(1,"UserName"), ExcelLibrary.ReadData(1, "Password"));
        }
        
        
        private static DataTable ExcelToDataTable(string filename)
        {
            FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read);
            IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);
            excelReader.IsFirstRowAsColumnNames = true;
            DataSet result = excelReader.AsDataSet();
            DataTableCollection table = result.Tables;
            DataTable resultTable = table["Sheet1"];
            return resultTable;
        }

       static List dataCol = new List();

        public static void PopulateInCollection(string fileName)
        {
            DataTable table = ExcelToDataTable(fileName);
            for (int row = 1; row <= table.Rows.Count; row++)
            {
                for (int col = 0; col < table.Columns.Count; col++)                 {                     Datacollection dtTable = new Datacollection()                     {                         rowNumber = row,                         colName = table.Columns[col].ColumnName,                         colValue = table.Rows[row - 1][col].ToString()                     };                     dataCol.Add(dtTable);                 }             }         }         public static string ReadData(int rowNumber, string columnName)         {             try             {                 string data = (from colData in dataCol                                where colData.colName == columnName && colData.rowNumber == rowNumber                                select colData.colValue).SingleOrDefault();                 //var datas = dataCol.Where(x => x.colName == columnName && x.rowNumber == rowNumber).SingleOrDefault().colValue;
                return data.ToString();
            }
            catch (Exception e)
            {
                return null;
            }
        }
    }

    public class Datacollection
    {
        public int rowNumber { get; set; }
        public string colName { get; set; }
        public string colValue { get; set; }
    }
}
Advertisements

Leave a Reply