Background: In the Selenium UI automation we all have been using Page Objects pattern as the "Best Practice" for years. In Page Objects "methods" are tightly coupled to pages instead of free-flowing well-abstracted functions. As per my observations, 70-80% Page objects methods code are not directly reusable in other web applications as every page object method is highly specialized to a specific page in a given web application.

We can also gain the same level of abstraction (if not better) with a well-abstracted set of simple UI functions as well by simply defining an objects collection (Object repository) and a set of well-defined utility functions to operate on it.

Then what exactly is the point of using page object pattern whereas we can use simple functions which can be composed together in different contexts. So, aren't we over coupling things in page objects?

Dilemma: Fundamentally, there is a handful of UI operations that we can perform in any UI automation. When we are defining methods in the context of a page, aren't we creating over specialized "methods" than generalized "context-free functions" ?

Example: The page object method like "click submit_user_button" which is specific to a page and might not be directly re-usable even in same application in other pages!

I strongly think, this is costing us flexibility=>reusability=>maintainability?

  • I have downvoted for a simple reason. I've found parsing and understanding long sentences hard. Could you perhaps reword your question by making sentences shorter, putting a dot everytime next part of your statement starts? – dzieciou Aug 21 at 12:09
  • 1
    I tried to rephrase it in shorter sentences. – V.A. Aug 21 at 20:59
  • Thanks. What do you mean by free-flowing well-abstracted functions? Can you given an example? Also, Object Repository seems to origin from QTP but to me it has vague meaning. Can you explain what is stored in Object Repository and give an example? I guess that there are both methods that are specific to certain pages, and methods that can be useful for different pages. Only by looking at examples I would be able to give more specific answer. – dzieciou Aug 22 at 12:38
  • By free flowing as the name implies, not tied to specifics like a page.Similarly object repository can be any data structure or format to store including Json, xml etc . – V.A. Aug 27 at 11:24

Isn't that what pageObjects are in essence: A description of the UI elements on a Page and how you can interact with them.

Now when writing tests you often interact with multiple elements in a certain way to achieve a workflow. Now if multiple tests use the same workflow it might make sense to move the combination of workflow-steps also into the pageObjects so other tests can re-use it. I wouldn't start with this, just keep it DRY.

Splitting all the UI elements and its interactions into pages and workflows just make it easier to read, understand how and when to use them.

I really don't get how this is overcomplicating things. Creating abstractions, decoupling and storing this in files of around 100 lines is what programmers do for a living.

When creating pageObjects don't over-engineer them from the start. Keep the YAGNI principles in mind.

What I like about well done page objects is that you decouple the driver of the browser from the tests. The tests interact with the pages, the pages with the driver. The tests don't know the driver. This means you could switch the driver from Selenium to Cypress without changing the tests in theory.

  • May be "overcomplicating" is not the right word. I mean 'overcoupling'.Changing it. – V.A. Aug 18 at 14:52
  • In large/complex UI based application s, we usually get page objects much larger than 100 lines. – V.A. Aug 27 at 11:41
  • Ah you mean those applications that try to put all features into a single screen/page, that is another enginering anti-pattern. I guess classes should ideally be around 100-500 lines. If you have pageObjects that are larger probably you have some sub-classes or you can split the page in areas. Also read:softwareengineering.stackexchange.com/questions/66523/… – Niels van Reijmersdal Aug 27 at 12:00

The term PageObjects has become greatly over-used (including by me).

To reset:

We have element locators.
Sometimes our element locators also have an action (such as click) with them.
Some element locators are at the page level but others can be considered to be at fragment, frame, workflow or domain specific grouping levels

These locators are then basically accessed in two ways - directly at the top layer of the test script, e.g. click user_submit_button or by your custom DSL which might be submit_user_form and then the function submit_user_form itself has the line click user_submit_button and user_submit_button is defined at the next lower, page object, level.

In either case the 2 key roles that the page object serves are:

  • reduce errors due to duplicate definitions of the same element
  • name the object to make it more readable and easier to maintain

You want the code to read more like

click submit_user_button

and not something like

click(find('div.users span#inputform button'))

Yes we are creating quite specific and selective and not general functions here but in this case general functions is simply not the only goal in writing this sort of specific test code. We are making code maintainable, that is the goal. I've seen code that didn't use Page Objects and it gets ugly looking fast.

  • As I understand, any specific code is less flexible so less reusable.And any less reusable code is less maintainable. Is n't it? – V.A. Aug 19 at 5:05
  • reusability is one attribute of good code, however it has to be balanced against others and for the specific situation allowing for other factors. programming is all about balancing multiple concerns – Michael Durrant Aug 19 at 11:04
  • reusability is good when appropriate. However when two objects are different things, giving them unique names is still good. – Michael Durrant Aug 19 at 11:09
  • For UI automation maintainability is the primary goal to achieve in code. Functions like 'click submit_user_button' and 'click_order_save_button' in different pages are a maintenance nightmare in the long run. – V.A. Aug 20 at 2:46
  • Also these so called page classes don't have any internal state to protect from outer world for mutation .We never change locator definitions during runtime. – V.A. Aug 20 at 3:04

Page objects work well in smaller sites where there is little to no re-use of fields because the coupling effect isn't significant enough to cause major issues - there will always be challenges finding a balance between readable tests, DRY, YAGNI, and SOLID.

I've found that once the application is large enough it's better to work in terms of input type objects, so that the test code is passing the locator information as well as any data to be entered.

This massively simplified my test code: I have an object to handle edit-type inputs, another for clickable fields (buttons, links, and so forth), another for checkboxes, one for dropdowns, and so forth. This allows my page object to be a single generic object that calls methods like FindAndClick(string id), FindAndEnterText(string id, string text) etc. (Then I data drive the test so that the ids, text etc. are read from a CSV file by the test harness).

  • You still should use the "classical" definition of page objects... it becomes way more important as your site and suite becomes larger. You can still have your specific functions to handle specific elements but those would be referenced/used inside your page objects. Page objects provide organization and your element functions provide a DRY way to deal with those elements on the pages. You can (and probably should) have both. – JeffC Aug 20 at 13:10
  • @JeffC - I found that it didn't work very well, because the site I work with has too many places where the only difference is the page an element is on. It becomes entirely too cumbersome to have to define a logoff element one every page except one, or to build an overly complex inheritance structure so that the header elements (which every page object would need to reference) can be accessed from pages. – Kate Paulk Aug 20 at 13:33
  • 1
    In that case, build a header panel page object and use it as needed. A page object doesn't have to represent an entire page, just any repeated functionality. You could have a calendar widget page object or a login dialog page object and so on. – JeffC Aug 20 at 13:37

As it seems to me, Page Objects does not introduce abstraction to the code since when you define a page object you do that for a specific element of the page. I would also not oppose Page Objects to Object Repository since basically object repositories are intended to store page objects.

When I use Page Object pattern, I can see the biggest value in possibility of combination of that architectural pattern with OOP conceptions and instruments that programming language provides.

For example you can define page objects bound to a class and then extend that class by adding other objects / hiding existing objects. This will help you follow the implementation of your application since this is the common practice to reuse UI components in different places of the application and to extend the components capabilities (what you can address with inheritance when use page object) for example depending on what the role a user has.

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.