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

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

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.

Now all the code that depends on the page can use the page as an interface. That means if you have to replace it, the new version only needs to implement the same interface.

The second improvement that we made was related to the previously called Validators classes. In general, they were holding assertion methods, so the first thing that we decided to do was to rename them to end with suffix Asserter. We did that because in the production code the validators are meant for a different job, like validating user’s input, not asserting things.

After that, another big refactoring that we applied was that the Asserter’s methods were used as extension methods of the page’s interface. As a result, they can be used as ordinary methods provided by the concrete page.

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.

As you can see from the example, the inheritance model is simplified compared to the previous versions.

The usage of the provided solution is straightforward.

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.

The second alternation was connected with the Asserter classes. Now they don’t extend the pages’ interfaces rather the pages themselves.

The only difference of the usage in tests is that now you can access the Map’s elements directly in tests.

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

The thing that I love most in the page objects, that we designed, is that the elements, page’s logic and assertions are placed inside different files. I believe that this makes the page objects a lot more understandable and readable. Additionally, it decreases the associated maintainability costs.

To simplify the inheritance tree even further, we decided to use partial classes instead of generic base classes. With the small adjustment of making the Map property public, we thought that it will be an excellent idea of putting the maps’ elements directly in the page. However, if they were combined in the same file, the design would have had the same drawbacks as the WebDriver’s one. It would have led to larger files where elements would have been mixed with the page’s service methods. We didn’t want that. The solution was to leave elements in a separate file, but now it is a partial class of the main page’s one.

This is how the new page map looks like. It uses the driver instance defined in the main page class.

There are some small changes in the main page class too. Now it inherits a simpler version of the BasePage which doesn’t require a generic element map parameter.

The usage of the new page objects is identical to the previously presented with the only difference that the page’s elements can be accessed directly from the page’s instance.

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.