Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / DevOps / testing

Page Object Design Pattern

4.91/5 (19 votes)
9 Oct 2015Ms-PL5 min read 58K  
Explains in detail how to implement Page Object Pattern- through the usage of the built-in feature in WebDriver and how to create it from scratch.

Introduction

In my new series of articles “Design Patterns in Automation Testing“, I am going to present you the most useful techniques for structuring the code of your automation tests. In my examples, I am going to use Selenium WebDriver. However, the patterns are abstract structures, and they can be implemented with any similar automation framework or programming language. One of the most popular patterns in Web Automation is the so called Page Object Pattern. To understand the primary goal of the pattern, first you need to think what your web automation tests are doing. They navigate to different web pages and click/type on/in various elements. The Page Object Pattern wraps all elements, actions and validations happening on a page in one single object- Page Object. I am going to show you two ways in which you can use this pattern. Through the usage of the built-in Page Objects in Selenium WebDriver and via manually created classes.

Image 1

Page Object Pattern via Selenium WebDriver

UML Class Diagram

Image 2

Participants

The classes and objects participating in this pattern are:

  • Page Object (BingMainPage) - Contains properties of all necessary web elements of the page. Also, there you can find all actions that can be performed (Search, Navigate). All validations can be placed here too.
  • UI Tests (BingTests) – This class contains a group of tests related to the above page; it can hold only a single instance of the page object.

Page Object Pattern C# Code

If you are not familiar with the WebDriver Framework, you can look into my article- Getting Started with WebDriver C# in 10 Minutes. To be able to use the page object pattern built-in feature of the framework, you need to install an additional NuGet Package - Selenium.Support.

Image 3

The automation test cases in the below examples will navigate to Bing, search for “Automate The Planet” and validate the count of the returned results. In this particular case, there is a need for only two classes - BingMainPage and the test class BingTests.

C#
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 ValidateResultsCount(string expectedCount)
    {
        Assert.IsTrue(this.ResultsCountDiv.Text.Contains(expectedCount), 
	"The results DIV doesn't contains the specified text.");
    }
}

There are two important things to highlight in the above example.

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

Just add a property with the desired name and place the above attribute with the appropriate properties - the type of the locator (Id, Class, CSS) and the value of the Locator.

Initialization of the Elements

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

The static method InitElements takes the responsibility to initialize all of the elements on the page the first time when the driver navigates to it.

Usage in Tests

C#
[TestClass]
public class BingTests
{
    public IWebDriver Driver { get; set; }
    public WebDriverWait Wait { get; set; }

    [TestInitialize]
    public void SetupTest()
    {
        this.Driver = new FirefoxDriver();
        this.Wait = new WebDriverWait(this.Driver, TimeSpan.FromSeconds(30));
    }

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

    [TestMethod]
    public void SearchTextInBing_First()
    {
        BingMainPage bingMainPage = new BingMainPage(this.Driver);
        bingMainPage.Navigate();
        bingMainPage.Search("Automate The Planet");
        bingMainPage.ValidateResultsCount("264,000 RESULTS");
    }
}

The main pros of the Page Object Pattern are the readability and that it follows the DRY (Do not Repeat Yourself) and Single Responsibility SOLID Principles. It helps you to build an easy to maintain test that does not use element locators directly.

Page Object Pattern without Selenium WebDriver

UML Class Diagram

Image 4

Participants

The classes and objects participating in this pattern are:

  • Page Object Element Map – Contains all element properties and their location logic.
  • Page Object Validator – Consists of the validations that will be performed on the page.
  • Page Object (BingMainPage)- Holds the actions that can be performed on the page like Search and Navigate. Exposes an easy access to the Page Validator through the Validate() method. The best implementations of the pattern hide the usage of the Element Map, wrapping it through all action methods.
  • UI Tests (BingTests) – This class contains a group of tests related to the above page; it can hold only a single instance of the page object.

Page Object Pattern C# Code

Using this approach, we don’t need anymore the Selenium.Support NuGet.

Paste all elements of the page in a new element map class.

C#
public class BingMainPageElementMap
{
    private readonly IWebDriver browser;

    public BingMainPageElementMap(IWebDriver browser)
    {
        this.browser = browser;
    }

    public IWebElement SearchBox 
    {
        get
        {
            return this.browser.FindElement(By.Id("sb_form_q"));
        }
    }

    public IWebElement GoButton 
    {
        get
        {
            return this.browser.FindElement(By.Id("sb_form_go"));
        }
    }
       
    public IWebElement ResultsCountDiv
    {
        get
        {
            return this.browser.FindElement(By.Id("b_tween"));
        }
    }
}

Paste all validation methods in a separate class.

C#
public class BingMainPageValidator
{
    private readonly IWebDriver browser;

    public BingMainPageValidator(IWebDriver browser)
    {
        this.browser = browser;
    }

    protected BingMainPageElementMap Map
    {
        get
        {
            return new BingMainPageElementMap(this.browser);
        }
    }

    public void ResultsCount(string expectedCount)
    {
        Assert.IsTrue(this.Map.ResultsCountDiv.Text.Contains(expectedCount), 
		"The results DIV doesn't contains the specified text.");
    }
}

At last, put together all classes in the Main Page Object.

C#
public class BingMainPage
{
    private readonly IWebDriver browser;
    private readonly string url = @"http://www.bing.com/";

    public BingMainPage(IWebDriver browser)
    {
        this.browser = browser;
    }

    protected BingMainPageElementMap Map
    {
        get
        {
            return new BingMainPageElementMap(this.browser);
        }
    }

    public BingMainPageValidator Validate()
    {
        return new BingMainPageValidator(this.browser);
    }

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

    public void Search(string textToType)
    {
        this.Map.SearchBox.Clear();
        this.Map.SearchBox.SendKeys(textToType);
        this.Map.GoButton.Click();
    }
}
By the way, during my research for the "Design Patterns in Automation Testing" series, I always first read about the presented pattern in several books. One of them that you might want to check is "Head First Design Patterns" by Eric Freeman. The author uses a very unique methodology for presenting the material that I haven't found anywhere else. Probably most of you will like it. For the more hardcore fans that might find the book too easy, I recommend the bible of the design patterns - "Design Patterns- Elements of Reusable Object-Oriented Software". It will change your way of thinking about object-oriented design.

Usage in Tests

C#
[TestClass]
public class BingTests
{
    public IWebDriver Driver { get; set; }
    public WebDriverWait Wait { get; set; }

    [TestInitialize]
    public void SetupTest()
    {
        this.Driver = new FirefoxDriver();
        this.Wait = new WebDriverWait(this.Driver, TimeSpan.FromSeconds(30));
    }

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

    [TestMethod]
    public void SearchTextInBing_Second()
    {
        POP.BingMainPage bingMainPage = new POP.BingMainPage(this.Driver);
        bingMainPage.Navigate();
        bingMainPage.Search("Automate The Planet");
        bingMainPage.Validate().ResultsCount("264,000 RESULTS");
    }
}

As you can see, the usage of the second type of page object pattern structure is identical to the previous one. Regardless, I like the second solution more because it follows the SOLID Principles more strictly. The different classes used in it have a stronger Cohesion.

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
  9. Observer Design Pattern
  10. Observer Design Pattern via Events and Delegates
  11. Observer Design Pattern via IObservable and IObserver
  12. Decorator Design Pattern- Mixing Strategies
  13. Page Objects That Make Code More Maintainable
  14. Improved Facade Design Pattern in Automation Testing v.2.0
  15. Rules Design Pattern
  16. Specification Design Pattern
  17. Advanced Specification Design Pattern

 

If you enjoy my publications, feel free to SUBSCRIBE
Also, hit these share buttons. Thank you!

Source Code

The post- Page Object Pattern in Automation Testing 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)