Home > Agile, BDD, C#, Selenium, TDD, Test Automation > Test Automation Framework in Page-Object pattern using C#, Selenium, SpecFlow and NUnit

Test Automation Framework in Page-Object pattern using C#, Selenium, SpecFlow and NUnit

Creating a Test Automation Framework is a challenging task due to following reasons:

  • Test framework design and the coding of that design requires significant time and effort
  • Test framework must be easy to expand and maintain
  • Test framework should be independent of application
  • Test design should remove most testers from the complexities of the test framework

Let me explain the creation of framework using the Page-Object pattern. Refer my previous blog for more info on this pattern.

SOFTWARE REQUIREMENTS:

  • Windows 7 as OS
  • Microsoft Visual Studio 2010 as IDE
  • SpecFlow as BDD tool for .Net
  • NUnit as Unit Testing Tool
  • Selenium as a Test Automation Tool

SET-UP INSTRUCTIONS:

Refer my previous blog on set-up instructions for creation and execution of automation tests using C#, Selenium, SpecFlow and NUnit.

Lets consider a test scenario:

Given I am on the Google home page
When I search for text selenium
Then I should see the search results

My task is to create a Page-Object pattern for the above test scenario. Contents in the files such as  GoogleSearch.feature and WebBrowser.cs are unchanged and I had defined the test actions using Selenium API within the GoogleSearchStepDefinition.cs file in my previous blog. Now, I need to apply the Page-Object pattern by creating a class for each web page. Create 2 class files as the test scenario has actions w.r.t 2 pages namely – GoogleHomePage.cs and GoogleSearchResultsPage.cs and this class file will be placed within a folder ‘Pages’ to separate from other class files. Now, I create methods within the GoogleSearchStepDefinition.cs file and these methods are executed within the page class GoogleHomePage.cs and GoogleSearchResultsPage.cs.

Copy and paste the code below to the  GoogleSearchStepDefinition.cs file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TechTalk.SpecFlow;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;
using System.Threading;
namespace SpecflowTest
{
 [Binding]
 public class StepDefinition1
 {
 [Given(@"I am on the Google home page")]
 public void GivenIAmOnTheGoogleHomePage()
  {
  var GoogleHP = new GoogleHomePage(WebBrowser.Current);
  GoogleHP.Navigate();
  }

 [When(@"I search for text (.*)")]
 public void WhenISearchForATextSelenium(string keyword)
  {
  var GoogleHP = new GoogleHomePage(WebBrowser.Current);
  GoogleHP.SearchOperation(keyword);
  }

 [Then(@"I should see the search results")]
 public void ThenIShouldSeeTheSearchResultsForSelenium()
  {
  var GoogleSRP = new GoogleSearchResultsPage(WebBrowser.Current);
  GoogleSRP.ValidateTest();
  }
 }
}

Copy and paste the code below to the  GoogleHomePage.cs file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TechTalk.SpecFlow;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;
using System.Threading;
using SpecflowTest;
namespace SpecflowTest
{
 class GoogleHomePage
 {
 private IWebDriver driver;

 //Contructor to re-use the driver
 public GoogleHomePage(IWebDriver driver)
 {
 this.driver = WebBrowser.Current;
 }

 public void Navigate()
 {
 //Navigate to the site
 WebBrowser.Current.Navigate().GoToUrl("http://www.google.com");
 //Check that the Title is what we are expecting
 Assert.AreEqual("Google", WebBrowser.Current.Title);
 }

 public void SearchOperation(string keyword)
 {
 // Find the text input element by its name
 IWebElement query = WebBrowser.Current.FindElement(By.Name("q"));
 // Input the search text
 query.SendKeys(keyword);
 // Now submit the form
 query.Submit();
 // Google's search is rendered dynamically with JavaScript.
 // Wait for the page to load, timeout after 5 seconds
 WebDriverWait wait = new WebDriverWait(WebBrowser.Current, TimeSpan.FromSeconds(5));
 IWebElement title = wait.Until<IWebElement>((d) =>
 {
  return d.FindElement(By.ClassName("ab_button"));
 });
 }
 }
}

Copy and paste the code below to the  GoogleSearchResultsPage.cs file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TechTalk.SpecFlow;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;
using System.Threading;
using SpecflowTest;
namespace SpecflowTest
{
 class GoogleSearchResultsPage
 {
 private IWebDriver driver;

 //Contructor to re-use the driver
 public GoogleSearchResultsPage(IWebDriver driver)
 {
 this.driver = WebBrowser.Current;
 }

 public void ValidateTest()
 {
 //Check that the Title is what we are expecting
 Assert.AreEqual("selenium - Google Search", WebBrowser.Current.Title);
 }
 }
}

Run the tests using NUnit and the tests will Pass. Now, we are almost 90% done with our task in the creation of a test framework in Page-Object pattern but we need to re-factor this pattern by creating a Base Page class. The need for the base class is to remove the redundant methods. In the GoogleHomePage.cs and GoogleSearchResultsPage.cs file, there is a redundant method on initializing the driver:

private IWebDriver driver;

 //Contructor to re-use the driver
 public GoogleSearchResultsPage(IWebDriver driver)
 {
 this.driver = WebBrowser.Current;
 }

So, create a Base Page class say BasePage.cs and move the above method on initialising the driver to the Base Page Class as shown below:

private IWebDriver driver;

 protected BasePage(IWebDriver driver, String loadUrl = "")
 {
 this.driver = WebBrowser.Current;
 WebUrl = loadUrl;
 }

Similarly, I have added a method on navigating to the webpage to the BasePage.cs as shown below:

private readonly string WebUrl;

public void GoToSite()
 {
 driver.Navigate().GoToUrl(WebUrl);
 }
 
 
Final contents of GoogleHomePage.cs as shown below:
             
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TechTalk.SpecFlow;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;
using System.Threading;
using SpecflowTest;
namespace SpecflowTest
{
 class GoogleHomePage : BasePage
 {
 private static readonly String Url = "http://www.google.com";
//Contructor to re-use the driver
 public GoogleHomePage(IWebDriver driver) : base(driver, Url)
 {
 }

 public void Visit(string Url)
 {
 GoToSite();
 //Check that the Title is what we are expecting
 Assert.AreEqual("Google", WebBrowser.Current.Title);
 }

 public void SearchOperation(string keyword)
 {
 // Find the text input element by its name
 IWebElement query = WebBrowser.Current.FindElement(By.Name("q"));
 // Input the search text
 query.SendKeys(keyword);
 // Now submit the form
 query.Submit();

 // Google's search is rendered dynamically with JavaScript.
 // Wait for the page to load, timeout after 5 seconds
 WebDriverWait wait = new WebDriverWait(WebBrowser.Current, TimeSpan.FromSeconds(5));
 IWebElement title = wait.Until<IWebElement>((d) =>
 {
 return d.FindElement(By.ClassName("ab_button"));
 });
 }
 }
}
      
    
Final contents of GoogleSearchResultsPage.cs as shown below:
      

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TechTalk.SpecFlow;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;
using System.Threading;
using SpecflowTest;

namespace SpecflowTest
{
 class GoogleSearchResultsPage : BasePage
 {
 //Contructor to re-use the driver
 public GoogleSearchResultsPage(IWebDriver driver) : base(driver)
 {
 }

 public void ValidateTest()
 {
 //Check that the Title is what we are expecting
 Assert.AreEqual("selenium - Google Search", WebBrowser.Current.Title);
 }
 }
}

 
 
Final contents of BasePage.cs as shown below:
     
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TechTalk.SpecFlow;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;
using System.Threading;
using SpecflowTest;
namespace SpecflowTest
{
 class BasePage
 {
 private IWebDriver driver;
 private readonly string WebUrl;

 protected BasePage(IWebDriver driver, String loadUrl = "")
 {
 this.driver = WebBrowser.Current;
 WebUrl = loadUrl;
 }

 public void GoToSite()
 {
 driver.Navigate().GoToUrl(WebUrl);
 }
}
}
 
 
Run the test using NUnit:

 
Advertisements
  1. November 1, 2012 at 11:28 am

    I think this is one of the most important information
    for me. And i’m glad reading your article. But should remark on few general things, The web site style is perfect, the articles is really nice : D. Good job, cheers

  2. Shikha
    January 17, 2013 at 9:49 am

    Thanks very much for ll the information you have provided here, very well thought and great examples. I believe for .Net with Selenium this is the best information I have come across. Please keep doing the great work in future.

  3. April 25, 2013 at 10:59 am

    Hi Anoop, thank you very much for this. I just joined a .net team and we are currently trying to implement specflow – currently I am looking at way to run our tests in a headless mode – any suggestions?

  4. January 14, 2014 at 9:33 am

    Can I simply just say what a comfort to
    discover somebody that actually understands what they are discussing on the web.
    You certainly know how to bring a problem to light and make it important.
    More people really need to check this out and understand this side of your story.
    I was surprised that you are not more popular since you definitely possess the
    gift.

  5. May 18, 2014 at 6:50 am

    Hi..
    Good to see info about framework. I have done a search for almost long time and found the below site as well along with your.

    The below website has also provided a framework structure, folder representation and steps to follow to design and implement a framework

    http://seleniumeasy.com

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: