Page Object Pattern Advantages & Implementation

The following tutorial is the next step in Learning how to create a test automation framework with C#, Selenium 3 and Nunit : this step is about Page Object Pattern (also known as Page Object Design Pattern or Page Object) and the reasons to implement it when creating your test automation framework.


Tutorial Overview:

Class 1 – Creating an Automated Test Using Selenium WebDriver 3 and C#

Class 2 – How to Create a Test Automation Framework Architecture with Selenium WebDriver 3

Class 3 – Utilizing Test Automation Framework with Advanced Capabilities


 Page Object Pattern

To this point, we were writing code with no actual structure, focusing only on a single page and its elements and sending commands to Selenium. However, what will happen when working with multiple pages, as most likely in an actual automation case?

We will prefer not to call a command dozens of times on a dozen of different pages in a product, due to unwanted code duplication and complicated code maintenance. In case the developers team decides to change the ID Attribute of the element.

Hence, the Page Object Pattern technique provides a solution for working with multiple web pages and prevents unwanted code duplication and enables an uncomplicated solution for code maintenance. In general, every page in our application will be represented by a unique class of its own and the page element inspection will be implemented in every class.

In this tutorial, we’ll be using more than one class (the same one the automated tests were executed from). We’ll begin using layers.

Let’s begin with calling each element from the class and operate the desired method. The following example will demonstrate this process in the best way:

We’ll be implementing the Page Object Pattern on the Contact Us page. First, let’s get back to the test automation project and create the new folder ‘Pages’. In this folder we’ll be creating a new class called ‘ContactUs’.

 

 

 

Copy the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.PageObjects;
using System.Threading;
using NUnit.Framework;
using System.IO;

namespace Test
{
    public class ContactUs
    {
        [FindsBy(How =How.Name,Using = "your-name")]
        private IWebElement yourName;

        [FindsBy(How = How.Name, Using = "your-email")]
        private IWebElement yourEmail;
        [FindsBy(How = How.Name, Using = "your-subject")]
        private IWebElement yourSubject;

        [FindsBy(How = How.Name, Using = "your-message")]
        private IWebElement yourMessage;

        [FindsBy(How = How.XPath, Using = "//input[@type='submit']")]
        private IWebElement submit;

        [FindsBy(How = How.ClassName, Using = "wpcf7-response-output")]
        private IWebElement SuccMessage;

        [FindsBy(How = How.Id, Using = "menu-item-1296")]
        private IWebElement contactUs;
        public bool isAt()
        {
            return Browsers.Title.Contains("Contact Us");
        }

        public void GoTo()
        {
            contactUs.Click();
        }

        public void SendYourName(string name)
        {
            yourName.SendKeys(name);
        }

        public void SendYourEmail(string email)
        {
            yourEmail.SendKeys(email);
        }

        public void SendYourSubject(string Subject)
        {
            yourSubject.SendKeys(Subject);
        }

        public void SendYourMessage(string massage)
        {
            yourMessage.SendKeys(massage);
        }

        public void clickSubmit()
        {
            submit.Click();
        }

        public void ValidateMessage()
        {
            try
            {
                var text = SuccMessage.Text;
            }
            catch (Exception e)
            {
                Assert.Fail();
            }
        }
    }
}

 

FindsBy attribute:

[FindsBy(How = How.Name, Using = “your-name”)]

private IWebElement yourName;

The tag will be on top of the object of the web element type. FindsBy receives 2 parameters for locating the element.

In the following example we’ll be locating the element by ‘Name’ while Using is the value of the Selector. For example:

 

 

In the same way we’ll map the elements on the Contact Us page.
After all the elements are mapped, lets create functions performing actions on these elements:

public void Goto()
{
    contactUs.Click();
}

public void SendYourName(string name)
{
    yourName.SendKeys(name);
}

 

GoTo function – clicks on the element on the navigation bar and navigates to the Contact Us page.

SendYourName function – sends values to the same field.

After creating the class handling our page, we’ll be implementing it by creating another class names ‘Pages’. This class will consist of the entire set of page objects we have. It’s going to be the only class that can communicate with each page.

Continue on by pasting the following code:

using OpenQA.Selenium.Support.PageObjects;

namespace Test
{
    public static class Pages
    {
        private static T getPages<T>() where T : new ()
        {
            var page = new T();
            PageFactory.InitElements(Browsers.getDriver, page);
            return page;
        }

        public static ContactUs contactUs
        {
            get { return getPages<ContactUs>(); }
        }
    }
}
  • private static T getPages<T>() – Creates a new instance to the specified page and returns the page.
  • public static ContactUs contactUs – Returns an instance of ContactUs page.

 

Using the same function (getPages) and generally this is the reason why it’s private, because it’s possible to call it solely from pages.

It’s important to mention that every page we instantiate, we’ll have to add it to the ‘Pages’ class because the page is accessible only via this class.

I’ll demonstrate with an example:

Assuming we will be writing automated tests and will want to click on the Contact Us page, the following command should be written:

Pages.contactUs.Goto();


Continue on to the Next step in the tutorial and Learn how to Read Data From CSV File in C#.

Feel free to leave your questions/ideas in the comment section below!