If you have read some of my previous posts, most probably you have checked some of my articles about Design Patterns in Automated Testing. One of the most prominent patterns that I have blogged about is the Page Object Pattern. It is so fundamental to the creation of a fast, robust and readable UI automation that I even dedicated to it a second article. In my team, we have applied it for a couple of years in different projects. During the process, we came up with a few different variations of the page objects. I believe that some of them lead to more readable and more maintainable code compared to the previously presented ones.
Page Objects v.2.0 - Interfaces
I like this pattern so much that I even created a fluent API for page objects. However, I think that its usage is a little bit troublesome, at least for me. It turned out that I am not a big fan of the Fluent Interface. If you have read my article on the subject, you may have found out that I suggested using the pages as singletons. Nonetheless, I think that there are more “cleaner” ways for doing this. The base singleton’s class and all other base generic pages make the code more unreadable and not so easy to grasp. We resolved this particular problem through the application of an IoC Container. Unfortunately, the page objects’ inheritance tree was still relatively complicated because of the two generic parameters.
IoC Container - Previous Version
public class BasePage<M>
where M : BasePageElementMap, new()
{
protected readonly string url;
public BasePage(string url)
{
this.url = url;
}
public BasePage()
{
this.url = null;
}
protected M Map
{
get
{
return new M();
}
}
public virtual void Navigate(string part = "")
{
Driver.Browser.Navigate().GoToUrl(string.Concat(url, part));
}
}
public class BasePage<M, V> : BasePage<M>
where M : BasePageElementMap, new()
where V : BasePageValidator<M>, new()
{
public BasePage(string url) : base(url)
{
}
public BasePage()
{
}
public V Validate()
{
return new V();
}
}
After a couple of discussions about the assertion methods, should they be part of the page objects, I started thinking about how can I improve them. On one hand, I wanted the assertions to be reused, on the other hand, they somehow shouldn’t have been directly part of the page objects. I thought that because they were the reason for the existence of the second base class with the additional generic parameter. Also, there was a new requirement- the pages to be interchangeable. In summary, if you have a Page A, later it is deprecated and its substitute is Page A1, it should be easy to exchange both implementations without breaking all the surrounding code.
Interfaces- Improved Version
public class SearchEngineMainPage : BasePage<SearchEngineMainPageMap>, ISearchEngineMainPage
{
public SearchEngineMainPage(IWebDriver driver)
: base(driver, new SearchEngineMainPageMap(driver))
{
}
public override string Url
{
get
{
return @"searchEngineUrl";
}
}
public void Search(string textToType)
{
this.Map.SearchBox.Clear();
this.Map.SearchBox.SendKeys(textToType);
this.Map.GoButton.Click();
}
}
To solve the lastly mentioned problem, we introduced a new participant of the Page Object Pattern- page’s interface. It defines what actions the page should be able to do.
public interface ISearchEngineMainPage : IPage
{
void Search(string textToType);
}
public static class SearchEngineMainPageAsserter
{
public static void AssertResultsCountIsAsExpected(this ISearchEngineMainPage page, int expectedCount)
{
Assert.AreEqual(page.GetResultsCount(), expectedCount, "The results count is not as expected.");
}
}
The only drawback of the presented implementation is that you always need to create a wrapper method of the asserted element because you don’t have a direct access to the page’s element map through its interface. However, these ideas resulted in eliminating the second base page and the additional generic parameter.
public abstract class BasePage<TMap>
where TMap : BaseElementMap
{
private readonly TMap map;
protected IWebDriver driver;
public BasePage(IWebDriver driver, TMap map)
{
this.driver = driver;
this.map = map;
}
internal TMap Map
{
get
{
return this.map;
}
}
public abstract string Url { get; }
public virtual void Open(string part = "")
{
this.driver.Navigate().GoToUrl(string.Concat(this.Url, part));
}
}
public class SearchEngineTests
{
private ISearchEngineMainPage searchEngineMainPage;
private IWebDriver driver;
public void SetupTest()
{
driver = new FirefoxDriver();
searchEngineMainPage = new SearchEngineMainPage(driver);
}
public void TeardownTest()
{
driver.Quit();
}
public void SearchForAutomateThePlanet()
{
this.searchEngineMainPage.Open();
this.searchEngineMainPage.Search("Automate The Planet");
this.searchEngineMainPage.AssertResultsCountIsAsExpected(264);
}
}
The tests use the pages as in the previously presented versions. The only subtle detail here is that if you want to be able to use the extension assertion methods, you need to add the using statement for the namespace, their class is in.

Two years ago while we were working on the first version of the BELLATRIX test automation framework, I did this research so that we can find the most convenient way for creating page objects.
Page Objects v.2.1 - Public Map, Skip Interfaces
As pointed in the subtitle, the next “generation” of page objects expose their element map to the code, that uses the page. Also, we decided that it is an overhead to create an interface for every particular page. Moreover, we found out that most of the time the interfaces of the substitute pages should be different from the old ones because different changes are applied to the pages. So the first subtle adjustment that we made was in the base page class, marking the Map property as public.
public abstract class BasePage<TMap>
where TMap : BaseElementMap
{
private readonly TMap map;
protected IWebDriver driver;
public BasePage(IWebDriver driver, TMap map)
{
this.driver = driver;
this.map = map;
}
public TMap Map
{
get
{
return this.map;
}
}
public abstract string Url { get; }
public virtual void Open(string part = "")
{
this.driver.Navigate().GoToUrl(string.Concat(this.Url, part));
}
}
The second alternation was connected with the Asserter classes. Now they don’t extend the pages’ interfaces rather the pages themselves.
public static class SearchEngineMainPageAsserter
{
public static void AssertResultsCountIsAsExpected(this SearchEngineMainPage page, int expectedCount)
{
Assert.AreEqual(page.Map.ResultsCountDiv.Text, expectedCount, "The results count is not as expected.");
}
}
The only difference of the usage in tests is that now you can access the Map’s elements directly in tests.
public void SearchForAutomateThePlanet()
{
this.searchEngineMainPage.Open();
this.searchEngineMainPage.Map.FeelingLuckyButton.Click();
this.driver.Navigate().Back();
this.searchEngineMainPage.Search("Automate The Planet");
this.searchEngineMainPage.AssertResultsCountIsAsExpected(264);
}
In my opinion, this is a good idea only if the nitty-gritty framework’s logic is hidden behind the page objects. I mean actions like clearing the text input before real typing, executing JavaScript calls and so forth.
For more detailed overview and usage of many more design patterns and best practices in automated testing, check my book “Design Patterns for High-Quality Automated Tests, C# Edition, High-Quality Tests Attributes, and Best Practices”. You can read part of three of the chapters:
Defining High-Quality Test Attributes for Automated Tests
Benchmarking for Assessing Automated Test Components Performance
Generic Repository Design Pattern- Test Data Preparation
Page Objects v.2.3 - Partial Pages
public partial class SearchEngineMainPage : BasePage
{
public IWebElement SearchBox
{
get
{
return this.driver.FindElement(By.Id("sb_form_q"));
}
}
public IWebElement GoButton
{
get
{
return this.driver.FindElement(By.Id("sb_form_go"));
}
}
public IWebElement ResultsCountDiv
{
get
{
return this.driver.FindElement(By.Id("b_tween"));
}
}
}
This is how the new page map looks like. It uses the driver instance defined in the main page class.
public partial class SearchEngineMainPage : BasePage
{
public SearchEngineMainPage(IWebDriver driver) : base(driver)
{
}
public override string Url
{
get
{
return @"http://searchEngineUrl/";
}
}
public void Search(string textToType)
{
this.SearchBox.Clear();
this.SearchBox.SendKeys(textToType);
this.GoButton.Click();
}
}
public void SearchForAutomateThePlanet_Second()
{
this.searchEngineMainPage.Open();
this.searchEngineMainPage.SearchBox.Clear();
this.searchEngineMainPage.SearchBox.SendKeys("Automate The Planet");
this.searchEngineMainPage.GoButton.Click();
this.searchEngineMainPage.AssertResultsCountIsAsExpected(264);
}

Pros
One of the biggest advantages of the proposed ideas is the single responsibility of the page’s classes.
In object-oriented programming, the single responsibility principle states that every class should have responsibility over a single part of the functionality, and that responsibility should be entirely encapsulated by the class.
In the presented implementation, the map class is responsible only for locating elements, the asserter class for asserting things and the page itself for providing service methods.
