Page objects for browser automation — 101
The page object model is a pattern used by UI automation testers to help keep their test code clean. The idea behind it is very simple — rather than directly using your test driver (Selenium / watin etc) you should encapsulate the calls to it’s API in objects that describe the pages you’re testing.
Page objects gained popularity with people that felt the pain of maintaining a large suite of browser automation tests, and people that practice acceptance test driven development (ATDD) who write their browser automation tests before any of the code to satisfy them — markup included — exists at all.
The common problem in both of these scenarios is that the markup of the pages changes, and the developer has to perform mass find/replaces to deal with the resulting changes. This problem only aggravates over time, with subsequent tests adding to the burden by re-using element selectors throughout the test codebase. In addition to the practical concern of modification, test automation code is natively verbose and often hides the meaning of the interactions its driving.
Page objects offer some relief — by capturing selectors and browser automation calls behind methods on a page object, the behaviour is encapsulated and need only be changed in one place.
Some page objects are anaemic, providing only the selector glue that the orchestrating driver code needs, while others are smarter, encapsulating selection, operations on the page, and navigation.
The simplest page object is easy to home roll, being little more than a POCO / POJO that contains a bunch of strings representing selectors, and methods that the current instance of the automation driver gets passed to. Increasingly sophisticated page objects capture behaviour and will end up looking like small domain specific languages (DSLs) for the page being tested.
The simplest page object could be no bigger than
public class Homepage
{
public string Uri { get { return "/"; } }
public string Home { get { return "#home-link"; } }
}
This kind of page object can be used to help cleanup automation code where the navigation and selection code is external to the page object itself. Its a trivial sample to understand, and effectively serves as a kind of hardcoded configuration.
A more sophisticated page object might look like this:
public class Homepage
{
public string Uri { get { return "/"; } }
public string Home { get { return "#home-link"; } }public void VisitHomeLink(RemoteWebDriver driver)
{
driver.SelectElementByCssSelector(Home).Click();
}
}This richer model captures the behaviour of the tests by internalising the navigation glue code that would be repeated across multiple tests.The final piece of the puzzle is the concept of Page Components - reusable chunks of page object that represent a site-wide construct - like a global navigation bar. Page components are functionally identical to page objects, with the single exception being that they represent a portion of the page so won't have a Uri of their own.By using the idea of page objects, you can codify the application centric portions of your automation suite (selectors, interactions), away from the repetitive test orchestration. You'll end up with cleaner and less repetitive tests, and tests that are more resilient to frequent modification.Page objects alone aren't perfect - you still end up writing all the boilerplate driver code somewhere, but they're a step in the right direction for your automation suite.