Page objects design pattern

Last Updated on by

Post summary: Description of code samples of Page Objects design pattern.

This is the most important pattern related to software automation. It enables you to create object repository with UI elements. Elements are separated from test logic. This pattern makes code much more maintainable and reusable.

References

This post is part of design patterns guide series. Code examples are located in GitHub for C# and Java.

Never do this

Without this pattern what you might do is start WebDriver, navigate to some test page. Locate element you need then click it.

IWebElement element = webDriver.FindElement(By.CssSelector("div.find label"));
element.Click();

This is good when you want to test the idea or do some quick demo. In a real-life project, this element might be needed in dozens of tests. What happens if the UI changes and CSS selector is not matching anymore? Here comes the maintainability problem, you have to search and replace all of them.

The proper way

In software engineering, there is a principle called DRY for short. Its idea is to have each element or action stored only once in a system. This avoids copy/paste and reduces the overhead for code maintenance. The same idea is used in Page Object pattern.

  • Each page or re-usable part of a page (i.e. header, footer, menu) is a separate class.
  • Class constructor takes WebDriver as an argument and uses it internally to locate elements.
  • Each element is a private property (or getter in Java).
  • Actions are public and internally operate with elements.

In the code below SearchField is private property used only by SearchFor method which is exposed to available action on HomePage. An element can be located inside the action method but suggested approach gives better readability. And if an element is needed more than once then defining it separately is a must.

public class HomePage
{
	private IWebDriver webDriver;

	public HomePageObject(IWebDriver webDriver)
	{
		this.webDriver = webDriver;
	}

	private IWebElement SearchField
	{
		get { return webDriver.FindElement(By.Id("search")); }
	}

	public void SearchFor(string text)
	{
		SearchField.SendKeys(text);
	}
}

The page object is instantiated in the test and actions are invoked.

HomePageObject homePage = new HomePageObject(webDriver);
homePage.SearchFor("automation");

With this approach, you have one element defined in only one place. Only actions are exposed out of the page object. It is very clear what actions can be done on this page.

Original page objects

To be honest what I have described in this post is not actually the original Page Objects pattern. Although the idea is same I have modified it slightly. Originally each action returns a page object. In this way, you can chain methods in one test and very easy to understand if a test will be broken when given action now returns different page object. I do not like chaining of methods though so I don’t need this extra. It doesn’t bother you at all to do

public HomePage SearchFor(string text)
{
	SearchField.SendKeys(text);
	return this;
}

Also, I have separated elements located outside of actions because I want better maintainability and readability of the code.

Conclusion

Always use page objects in your test automation. ALWAYS!

Related Posts