Selenium PageObjects and PageFactory in C#

PageObject Design Pattern

The PageObject Design Pattern models areas of an UI as objects within test code which can also be considered as Object Repository for Web UI Elements. The functionality classes (PageObjects) in this design represent a logical relationship between the pages of the application. Each class is referred to as a PageObjects and returns other PageObjects to facilitate the flow between pages. Page Object class is responsible to find the WebElements of that page and also hold methods that perform operations on those WebElements.

Because PageObjects are returned, it becomes necessary to model both successful and unsuccessful events that can occur when interacted with a page.

For example, consider logging into Gmail. After entering the user details, the step either passes and navigates to the Inbox page or stays on the Login page possibly due to invalid input parameters. A pass would then return the Inbox PageObject whereas a fail would return the Login PageObject.

This means better tests, exception handling and reporting. It may sound a little confusing, but its quite a simple yet an elegant approach to write your tests. PageFactory in C# helps us to follow the same approach in an easy way.

Advantages of using Page Object Pattern:

  • Easy to Maintain
  • Easy Readability of scripts
  • Reduce or Eliminate duplicacy
  • Re-usability of code
  • Reliability

PageFactory in C#

The PageFactory in C# Class is an extension to the Page Object Design Pattern. It is an inbuilt POM concept for Selenium WebDriver but it is very optimized. It is used to initialize the elements of the Page Object or instantiate the Page Objects itself. Annotations for elements can also be created (and recommended) as the describing properties may not always be descriptive enough to tell one object from the other.

It is used to Initialize Elements of a Page class without having to use 'FindElement' or 'FindElements'. Annotations can be used to supply descriptive names of target objects to improve code readability.

@FindBy Annotation

As the name suggests, it helps to find the elements in the page using By strategy. @FindBy can accept TagName, PartialLinkText, Name, LinkText, Id, Css, ClassName, XPath as attributes. An alternative mechanism for locating the element or a list of elements. This allows users to quickly and easily create PageObjects.

[FindsBy(How = How.Id, Using = "username")] private IWebElement UserName { get; set; }

The above code will create a PageObject and name it as UserName by finding it using its ID locator.

InitElements

This Instantiate an Instance of the given class. This method will attempt to instantiate the class given to it, preferably using a constructor that takes a WebDriver instance as its only argument or falling back on a no-arg constructor. An exception will be thrown if the class cannot be instantiated.

PageFactory.InitElements(WebDriver, PageObject);

Parameters:

  • WebDriver - The driver that will be used to look up the elements
  • PageObjects - A class which will be initialised

Returns: An instantiated instance of the class with WebElement and List<WebElement> fields proxied

PageFactory NameSpace

PageFactory functionality resides in OpenQA.Selenium.Support.PageObjects.

How to Implement PageFactory in Selenium Framework

In the last chapter of the Selenium Automation Framework, we chose one Login Test Case to automate. Let's see how PageFactory in C# works in the real world:

Create Home Page Objects

  1. Create a New Folder and name it as PageObjects. This can be done by doing Right Click on OnlineStore in the Project Solution and select Add >> New Folder.

  2. Create a New Class file and refer it as HomePage. This can be done by doing Right Click on PageObjects folder in the Project Solution and select Add >> New Item...

HomePage PageObject Class

using OpenQA.Selenium;
using OpenQA.Selenium.Support.PageObjects;

namespace OnlineStore.PageObjects
{
    class HomePage
    {
        private IWebDriver driver;

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

Note: As of now we are just using one object from Home Page and that is MyAccount link, add this element to HomePage page object.

Create LogIN Page Objects

  1. Create a New Class file and refer it as LoginPage.

  2. LogIn page has three important objects to add, which we are interested in using in the test.(Username textbox, Password textbox & Submit button)

LoginPage PageObject Class

using OpenQA.Selenium;
using OpenQA.Selenium.Support.PageObjects;

namespace OnlineStore.PageObjects
{
    public class LoginPage
    {
        private IWebDriver driver;

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

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

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

Note: HOW can be used with not just ID, it can be used with other attributes like TagName, PartialLinkText, Name, LinkText, Css, ClassName & XPath.

Write Test for LogIN Functionality

  1. Create a New Class file in the TestCases folder and refer it as LogInTest. Then create a Test method in it with [Test] annotation of NUnit Framework.

  2. Write the test using HomePage & LoginPage page objects.

LogInTest.cs TestCase

using NUnit.Framework;
using OnlineStore.PageObjects;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.PageObjects;

namespace OnlineStore.TestCases
{

    class LogInTest
    {
        [Test]
        public void Test() {

            IWebDriver driver = new FirefoxDriver();
            driver.Url = "https://www.store.demoqa.com";

            var homePage = new HomePage();
            PageFactory.InitElements(driver, homePage);
            homePage.MyAccount.Click();

            var loginPage = new LoginPage();
            PageFactory.InitElements(driver, loginPage);
            loginPage.UserName.SendKeys("TestUser_1");
            loginPage.Password.SendKeys("Test@123");
            loginPage.Submit.Submit();
        }    

    }
}

Note: Please create your own User Credentials for the test.

You will notice that once you type homePage in your test script and the moment you press dot, all the methods in the Home Page will display. We can expose methods in order to reduce duplicated code. We are able to call these methods multiple times. This will ensure a better maintainable test code, because we only have to make adjustments and improvements in one particular place.

Run the test from the Test Explorer and see how beautifully PageFactory initializes all the page objects and handle those objects to you test to carried on the execution.

Project Explorer

Your Project explorer window will look like this now.

PageObjectModel_2

Set Up Project for Selenium Automation Framework in CSharp
Set Up Project for Selenium Automation Framework in CSharp
Previous Article
PageFactory CacheLookup
PageFactory CacheLookup
Next Article
Lakshay Sharma
I’M LAKSHAY SHARMA AND I’M A FULL-STACK TEST AUTOMATION ENGINEER. Have passed 16 years playing with automation in mammoth projects like O2 (UK), Sprint (US), TD Bank (CA), Canadian Tire (CA), NHS (UK) & ASOS(UK). Currently, I am working with RABO Bank as a Chapter Lead QA. I am passionate about designing Automation Frameworks that follow OOPS concepts and Design patterns.
Reviewers
Virender Singh's Photo
Virender Singh

Similar Articles

Feedback