When trying to design a framework, it’s important to understand that while there is no right or wrong way to do it, there are still good ways to do it. Designing your framework to allow tests to be created within a certain way is just good practise.
There are three main design patterns that people recognise and adhere to, but that’s not to say there aren’t more, but by familiarising yourself with these three you will be putting yourself in a good position when it comes to understanding the basics of framework design. So let’s dive right in and take a look. I will only cover each one briefly in this article, and there will be follow up articles covering each one with code examples.
Number one in the list, and probably the most popular is the Page Object Model design.
The Page Object Model design principle is about breaking a web application or website in to its individual pages and create a class, or a PageObjects class for each of these pages. Each of these classes wraps elements, actions and validations in to one single object. Why is this important? Well think about how you navigate around a website, quite a lot of the time there is no real strict journey you have to follow. You can move from page to page, in various orders and still have the same result at the end as you would following a different route around the site.
So if you were to try and create a class dealing with several pages within one class, and having to assume how a user will interact with the system you’re trying to test then not only is that bad testing practise, it’s also a poor and difficult to maintain class. If that assumed journey gets changed and is no longer possible, then not only do you have to update your class, but now your tests might be completely useless due to them being written around that single class.
By putting pages in to single classes, your framework and tests automatically gain more modularity and allow for more flexibility in UI design changes.
So in tests where we are performing actions on a single page, we only need to create a single object for our PageObjects. And from here we can access all the wrapper methods we created to perform actions on a page. It’s worth noting that while we could in theory access elements directly, that would require using WebDriver code in the test itself, which isn’t good practise, but we’ll cover more on that later.
Where this approach starts to become less beneficial is when we have a system that has a more structured flow and follows set user journeys that we can’t really break away from. While it would still be more than acceptable to use, we could instead look at a design pattern that lends itself more to this kind of system, which is number 2 on our list, the Facade Design Pattern.
Facade looks at breaking classes down in to journeys, let’s look at an example where this would work. Take Amazon for example, when you buy something and go to the checkout, the journey that you follow is always the same. You enter your details, your delivery address, payment details then confirm. You know that no matter what it is you buy, you’re always able to follow the same checkout process. So an example like this, while you could certainly follow the Page Object pattern, it would mean creating multiple objects in a test, and the test itself will become quite long dealing with moving between pages and the kind of methods used to do that.
However with Facade, you could create a class that deals exclusively with that journey. So in your test, you’re still only creating one object, that calls a method dealing with all of your page classes. Let me take a step back for a second as I appreciate I could have just confused you there by mentioning page objects when talking about Facade.
With Facade, you’d still have all your page object classes for each individual page like you would in the Page Object Model. And in these you would still wrap your elements in actions and validations, but this time you’d then have an extra class that would be used to group all these with methods for your journey.
Going back to our above example. You’d have your EnterDetailsPage, DeliveryDetailsPage, PaymentDetailsPage and ConfirmPage classes. But this time you’d create a class called CheckoutFacade. This would contain a method that went from start to finish of that journey, calling all the relevant methods from each individual page class. And your test would create an instance of this class to test that journey. And that, in a nutshell, is Facade.
Last but not least is the Factory Design Pattern. This one is quite different from the other two in its approach. With some websites, when navigating around, the pages or content you see might not be known at the start, but relies on user input or external factors such as the browser or whether it’s being viewed on a mobile. These types of websites can be particularly challenging to automate as knowing exactly what page to instantiate in a test might not be at all obvious or even possible using other design patterns.
With a factory however, you create your classes in a way that allows them to determine what page you need in a test. Don’t let that worry you, it’s not quite as clever or complicated as it sounds. Pretend you have a site that has different content depending on whether you select you’re a male or a female at the start. The landing page after making that choice is completely different, but the journey itself is the same. Something as simple as a parameter in your constructor for your page object can be used, and in the constructor would be a switch statement that would fire up the correct landing page based on the parameter passed in. Although it’s an extremely simple example of a factory, that logic and that way of thinking is following the Factory Design Pattern. From there, you can follow the principles of either Page Object Models or Facade.
Including factories in your framework allows your to deal with systems that have dynamic content at certain points. But these factories don’t have to include complex logic and it’s important to remember that so not to be put off using it.
This article has touched upon some common design patterns used for designing test automation frameworks. In the next article, we’ll look in to Page Object Model a bit more and how we can write our page object classes, as well as how to write a test using this easy to use approach.