Facade pattern hides the complexity of objects creation under an interface which is exposed to a client. Using it, you can get access to different functions from the whole system without having to be worried about the implementation complexity.
A useful thing to consider is that facade is a part of the structural design patterns, which in general are used to combine object and classes to provide more complex functionalities. In another train of thoughts, the facade also known as the beautiful face of the building is nothing more than another layer over an existing implementation.
In automation testing, it could also be applied and its best applicability is in a mixed-use with page object pattern. How so? Well, on page object, you define multiple pages where you encapsulate different actions specific to a group of UI sections. But if it happened to have dozens of pages, it becomes pretty difficult to create different flows using different objects. Applying a face to the existing pages, your tests will be easier than never, so you have to import it and use it (as an entry point to all the pages).
Step 1 – The actual facade
Going further, let’s implement it. First, we have to define our facade. But it’s so easy, so just think how many pages you have, and implement a static method for each one. So as an example
get_home_page will return
HomePage class or
get_search_page will return the
HomePage, etc. So you can add as many pages as you want here. Apart from those, there is one more functionality added here (the
__driver and its getter), as it is required by all the pages.
class FacadePage: """ Facade class delegates the client requests to the actual subsystems """ __driver = get_selenium_driver('chrome') def get_driver(self): """ :return: selenium driver """ return self.__driver @staticmethod def get_home_page(): """ Implement home page sub-system :return: HomePage class """ return HomePage(FacadePage.__driver) @staticmethod def get_search_page(): """ Implement search page sub-system :return: SearchPage class """ return SearchPage(FacadePage.__driver)
Let’s reuse the page object to define the subsystems used by our facade.
See below a page example which was also presented in our first tutorial.
class HomePage(BasePage): """ Home page """ SEARCH_CONTAINER = 'searchInput' SEARCH_BUTTON = 'searchButton' CREATE_ACCOUNT = 'pt-createaccount' LOGIN = 'pt-login' def set_search_query(self, query: str): """ Search for a string :param query: string you are looking for """ self._driver.find_element_by_id(HomePage.SEARCH_CONTAINER).send_keys(query) def check_search(self): """ Check search button is visible """ return self._driver.find_element_by_id(HomePage.SEARCH_BUTTON).is_displayed() def search(self): """ Click on search button """ self._driver.find_element_by_id(HomePage.SEARCH_BUTTON).click()
Step 3 – Testing
Previously we’ve followed the unit testing approach, but for this article, we will keep it simple defining a simple call.
facade = FacadePage() driver = facade.get_driver() driver.get('https://en.wikipedia.org/') facade.get_home_page().set_search_query('Wiki')
Step 4 – Conclusions
As a result, Facade pattern is an easy solution for test automation, especially when you want to control in a beautiful manner the whole page implementation logic using just a page.
More details about the implementation could be found here