So you have started writing automation, you kept the principals of clean code (If not, read these posts: 1. How to write proper automation test; 2. Clean code in automation, is it essential?), and in general you are pleased with the result, but you still feel there is a lot of overhead and duplication in your code that you would like to avoid + now you must hire Selenium proficient QAs to work on the automated tests (or to spend the time to train them).
Hmmmm… That could be an ordeal now, right?
Let’s talk about the Page Object design pattern…
What is it exactly?
Well, PageObjects are some sort of an API to a page (or a view) you have in your system, let’s think of it as more as “Services” the page gives the tester…
A Page Object knows the internal of its matching HTML page (or view) and it alone knows it…
For example, if we would like to perform login (as a user) we are provided with these services:
- We type a username in the username input.
- We can type a password in the password input.
- We can click on the ‘Login’ button (Expecting failure or success).
Of course, there are more “Services” given, but we can stop here and get back to the point… What are we supposed to do with these “Services”? That’s the easy part:
We need to create a “LoginPage” object that knows the (private) selectors of the page and the HTML construct (ids, classes, xpaths and so on…). What is public to the tester? The services we just talked about above…
A tester can ask the login page to “TypeUsername(string inputUsername)” or TypePassword(string inputPassword) – You can also add “Services” like “LoginAsDefaultUser()” if you are using this page to test other pages…
While this a good start, it leaves a lot of room for improvement.
The most obvious problem is that there are common actions we will likely need across multiple Page Objects. And with our current approach, we would end up with duplicative code.
When creating a BasePage Object that wraps Selenium core, and each page Inherit from this page (directly or indirectly) we are creating a dynamic environment that is not coupled and if somewhere a page (or view) has change you need to fix only one specific object.
Why? How? By whom?
- Why – It was discussed above, but I will add here, it is the proper software engineering way to go… treat your automation code as if it was a real product, otherwise, you will reach a point it will not be maintainable.
- How and by whom? – I started by saying, that you probably need to hire only Selenium profound QAs now, but with this solution, the test writer doesn’t write selenium, he uses a page object language you created, and the Selenium ninjas are still a small team using their skills to add / change / maintain the page objects and “Services”.
- Even though it is called the Page Object design pattern, it is more as a View Object design pattern, for example: If in your platform there is a left menu that returns on every page you can create the “MyPlatformBasePage” and every view will inherit from it (and code duplication is gone yet again, Victory!)
- Page Objects exposes ONLY the “Services” provided, do not expose Selenium internals.
- Page Object is not a test, Do not assert its results.
- Methods return other PageObjects, For example: LoginPage that invoke the ‘LoginAsDefaultUser’ will navigate us to our applications home page so we must return our “HomePage” object.
- Use clean code principals, different “Services” provided by you will be represented with different methods, do not pass booleans to change the logic of a “Service”.