You are here

You are here

6 rules for high-quality page object patterns

public://webform/writeforus/profile-pictures/2016-10-28_16.10.45_0.jpg
Nikolay Advolodkin CEO and Senior Test Automation Engineer, Ultimate QA
 

The page object pattern is one of the most important aspects of thorough user interface (UI) test automation. But in my experience, eight out of 10 test automation engineers ignore it—even though it's been around for more than 15 years. Given the usefulness and effectiveness of page object patterns, ignoring them should be added to your list of test automation mistakes you don't want to make.

By creating a layer of abstraction between your automated functional tests and the target web page, page object patterns decrease sources of duplication. In other words, you create a single class for a single web page, then use that class in your automated functional test to interact with the web page in the same way you would manually.

This is a tried-and-tested pattern that works—but only when properly followed. The solutions architects I work with use page object patterns all the time, and it's easy to see why: It's a straightforward, effective system that yields results.

It's easy to trick yourself into thinking that all good solutions must be complicated, but this isn't the case with page object patterns and test automation. The most straightforward solutions are often the best, so add this to your list of test automation resources

Here's what you need to know to use page object patterns well in your automation efforts.

1. Create a great name for your page object class

Make sure the name you choose makes it 100% clear what's inside that page object. If you cannot do that, then your page object probably does too much. 

Take a look at the SauceDemoLoginPage below, which represents the login page of an app. After reading the class name, what kind of methods and properties would you guess would be inside?

It's unlikely that you'll be surprised by what you find inside the SauceDemoLoginPage class. On the other hand, imagine if the class with the same code was called SaucePageObject(). Upon reading this you'd have no clue what this class actually represents—and you could be surprised by what you find inside.

2. The page class should only contain methods for interacting with the HTML page or component

The only public methods you should allow in your page objects are ones that an end user can perform to your web application—nothing more. Consider the HTML page below. There are only two actions that the end user can perform; Open() and Login(). Hence, the implementation of SauceDemoLoginPage.cs above.

The end user of the app doesn't ConnectToSQL(), OpenExcel(), or ReadPDF(). As such, these methods have no place in your automated UI tests. By extension, this means that they cannot be publicly accessible in your page objects.

Imagine if you have 50 tests that call OpenExcel(). As you get more advanced and realize that Excel might not be the best place for your test data, you might start using the data from an API or JSON or CSV.

At that point, you'd need to update these 50 tests to use the new method, but not because the requirements of the application changed. Instead, you need to update them because you've exposed methods in your test that don’t have anything to do with the functionality of the software.

3. The page class should contain properties and methods, or be composed of objects that expose access

By using page objects, you can interact with the application through a single interface: the page object. If you want to interact with the login page, you do so through the SauceDemoLoginPage class.

For example, you might want to log in to the SauceDemoLoginPage by using 

Login("username", "password");

In this case you need to avoid the locators living in a separate class, since they're not necessary and will just overcomplicate your code.

You'll read plenty of articles that say that, by separating methods from properties for a page object, you will maintain the single responsibility principle (SRP). But that's not correct. In SRP, the responsibility is derived from an actor whose changing requirements will force you to make an update to your page object. If there is more than one such actor, then the module or page object has more than one responsibility.

Strictly speaking, the developer is the only actor that can force you into a change in your class. No one else would have the requirement to modify HTML elements without also modifying the HTML methods.

Ultimately, it's critical to avoid separating your locators from methods for a page object. It's unnecessary; it's over-optimization. That being said, a page could be composed of multiple components that are relevant to that page object.

4. A page object doesn't have to be an entire HTML page, and can be a small component

This is what programmers call "composition." The aim is to push pages toward composition rather than having to use inheritance. Below, you'll see how to use composition to create cleaner and tighter page objects.

 

In this example, the Car is composed of an Engine and Wheels, and Engine is a class that holds operations and properties of a car engine.

In a similar fashion you can break up your large page objects to be composed of multiple components. Notice in the ProductsPage example below how it is made of a CartComponent and a FooterComponent. The CartComponent performs operations related to a shopping cart, and the FooterComponent is the footer of the application. 

Notice how this ProductsPage follows the other three principles as well. There are no surprises about what is inside the class or the methods that are publicly exposed.

Make the most of your page objects

Simple page objects are an underrated technique. They are highly effective and easy to use, and provide you with code that is easy to read and maintain. Page object patterns are tried and true, and they work well. You just need to know how to use them to get results.

Keep learning