Click here to Skip to main content
15,867,704 members
Articles / Programming Languages / C#

Enhanced Selenium WebDriver Page Objects through Partial Classes

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
16 Apr 2017Ms-PL3 min read 6.6K   1  
Find how to create more refined and more maintainable page objects in WebDriver. These page objects will follow more closely the Single Responsibility Principle.

Introduction

One of the most popular design patterns in Web Automation is the so-called Page Object Pattern. The famous programmer Martin Fowler was one of the first that mentioned Page Object as a pattern and explained its usage. You may not be able to find it in the list of all "official" design patterns because the community started using it recently. Most of the other design patterns have been about for more than 20 years. You can find more about the usage of design patterns in the automated testing in my series- Design Patterns in Automated Testing Series.

In general, a page object abstracts an HTML page. It provides an easy to use interface for manipulating the page elements without searching for them in the HTML.

Selenium WebDriver Page Objects

C#
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.PageObjects;

namespace ImprovedPageObjects
{
    public class BingMainPage
    {
        private readonly IWebDriver driver;
        private readonly string url = @"http://www.bing.com/";

        public BingMainPage(IWebDriver browser)
        {
            this.driver = browser;
            PageFactory.InitElements(browser, this);
        }

        [FindsBy(How = How.Id, Using = "sb_form_q")]
        public IWebElement SearchBox { get; set; }

        [FindsBy(How = How.Id, Using = "sb_form_go")]
        public IWebElement GoButton { get; set; }

        [FindsBy(How = How.Id, Using = "b_tween")]
        public IWebElement ResultsCountDiv { get; set; }

        public void Navigate()
        {
            this.driver.Navigate().GoToUrl(this.url);
        }

        public void Search(string textToType)
        {
            this.SearchBox.Clear();
            this.SearchBox.SendKeys(textToType);
            this.GoButton.Click();
        }

        public void AssertResultsCount(string expectedCount)
        {
            Assert.AreEqual(this.ResultsCountDiv.Text, expectedCount);
        }
    }
}

In the example, the different properties represent the various elements of the pages. They are located through the help of the FindsBy attributes that are holding the finding strategy. Below them, you can find the different actions that can be performed on the page.

To use the code from the example, you need to install two NuGet packages - Selenium.WebDriver (holding the main WebDriver interfaces) and Selenium.Support (provides the page objects' support). If you use Selenium WebDriver on a daily basis maybe, you will find the cheat sheet that I created to be useful.

Image 1

The usage in tests is straightforward. You only create an instance of the page and call some of the action methods and at the end - one of the assertions.

C#
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;

namespace ImprovedPageObjects
{
    [TestClass]
    public class BingTests
    {
        private IWebDriver driver;

        [TestInitialize]
        public void SetupTest()
        {
            this.driver = new FirefoxDriver();
            this.driver.Manage().Timeouts().ImplicitlyWait(new TimeSpan(0, 0, 30));
        }

        [TestCleanup]
        public void TeardownTest()
        {
            this.driver.Quit();
        }

        [TestMethod]
        public void SearchTextInBing_First()
        {
            var bingMainPage = new BingMainPage(this.driver);
            bingMainPage.Navigate();
            bingMainPage.Search("Automate The Planet");
            bingMainPage.AssertResultsCount("236,000 RESULTS");
        }
    }
}

What Is the Problem with this Approach?

If you automate a page with lots of elements and complex logic, the code of the class can get enormous. Larger files increase the search time and decrease the readability of the page object. This is so because the class contains three different types of elements. The web page properties, the action methods and the assert methods. Usually, when you need to fix something in the page object, you need to change only one of these items.

One way to handle this problem is to separate these three types in different files. However, I want the usage of the page object to stay the same. You can use one of the features of C# - the partial classes.

Enhanced Page Objects through Partial Classes

You can read more about the partial classes and methods in the official MSDN documentation. But in general, it is possible to split the definition of a class over two or more source files. Each source file contains a section of the type or method definition, and all parts are combined when the application is compiled. Using this approach, the BingMainPage classes' definition will be placed inside three different files:

  • BingMainPage - contains the constructor(s) and the action methods
  • BingMainPage.Map - stores all web elements' properties
  • BingMainPage.Asserter - holds all assertions

BingMainPage

C#
using OpenQA.Selenium;
using OpenQA.Selenium.Support.PageObjects;

namespace ImprovedPageObjects.ImprovedVersion
{
    public partial class BingMainPage
    {
        private readonly IWebDriver driver;
        private readonly string url = @"http://www.bing.com/";

        public BingMainPage(IWebDriver browser)
        {
            this.driver = browser;
            PageFactory.InitElements(browser, this);
        }

        public void Navigate()
        {
            this.driver.Navigate().GoToUrl(this.url);
        }

        public void Search(string textToType)
        {
            this.SearchBox.Clear();
            this.SearchBox.SendKeys(textToType);
            this.GoButton.Click();
        }
    }
}

BingMainPage.Map

C#
using OpenQA.Selenium;
using OpenQA.Selenium.Support.PageObjects;

namespace ImprovedPageObjects.ImprovedVersion
{
    public partial class BingMainPage
    {
        [FindsBy(How = How.Id, Using = "sb_form_q")]
        public IWebElement SearchBox { get; set; }

        [FindsBy(How = How.Id, Using = "sb_form_go")]
        public IWebElement GoButton { get; set; }

        [FindsBy(How = How.Id, Using = "b_tween")]
        public IWebElement ResultsCountDiv { get; set; }
    }
}

BingMainPage.Asserts

C#
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ImprovedPageObjects.ImprovedVersion
{
    public partial class BingMainPage
    {
        public void AssertResultsCount(string expectedCount)
        {
            Assert.AreEqual(this.ResultsCountDiv.Text, expectedCount);
        }
    }
}

The usage of the page object in tests stays the same.

So Far in the "Design Patterns in Automated Testing" Series

  1. Page Object Pattern
  2. Advanced Page Object Pattern
  3. Facade Design Pattern
  4. Singleton Design Pattern
  5. Fluent Page Object Pattern
  6. IoC Container and Page Objects
  7. Strategy Design Pattern
  8. Advanced Strategy Design Pattern

The post Enhanced Selenium WebDriver Page Objects through Partial Classes appeared first on Automate The Planet.

All images are purchased from DepositPhotos.com and cannot be downloaded and used for free.

License Agreement

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
CEO Automate The Planet
Bulgaria Bulgaria
CTO and Co-founder of Automate The Planet Ltd, inventor of BELLATRIX Test Automation Framework, author of "Design Patterns for High-Quality Automated Tests: High-Quality Test Attributes and Best Practices" in C# and Java. Nowadays, he leads a team of passionate engineers helping companies succeed with their test automation. Additionally, he consults companies and leads automated testing trainings, writes books, and gives conference talks. You can find him on LinkedIn every day.

Comments and Discussions

 
-- There are no messages in this forum --