Introducing Page Object Pattern in iOS
The practice that makes UI test codes clean and scalable.
When you write UI tests, you might often think they are too complicated and do not follow DRY principle. So, to tackle this issue, I’d like to introduce Page Object Pattern for scalable UI testing in iOS.
What is Page Object?
Page Object is a class that represents a page of an application. It provides operations or interactions for a page, and a state of a page for assertions.
In this article, I will explain the motivation and practical examples.
What Is Wrong with UI Testing?
When we use XCUITest, you can easily simulate interactions such as tapping on UI elements and reading their states by calling their respective methods. Usually, when we write test codes to satisfy a scenario, the code can become too long. Let’s consider the Signup flow below:
If we write a test for this flow, it would resemble something like:
What are the core issues here? First of all, we will probably write a very similar code if we write a slightly different scenario. Secondly, It is hard to understand the intention of the code that tests the app and reads the states of the app. What we should understand from a scenario are only the sequential operations inside the pages and assertions of the states. Moreover, having to write the comments in the above code is a sign of a lack of abstraction. To resolve these, we need to abstract UI into sizable chunks that are reusable. So, let’s think about the concept of “Page” or “Screen”. How about creating a class for “Page” that has methods or properties for operations and states? We can write concise code which is reusable in another scenario, can’t we?
Test code with Page Object
Using Page Object, we can write a code like below. We can clearly understand how it operates and which page it moves to.
About Implementation
Now, I’ve explained the overview and the motivation of “Page Object”. From here, I’d like to explain how we implement it. First, we will create “Page” protocol. “Page” protocol has 2 properties: app
and view
. It has app
for the context of a Page. It is used only for defining view
and other Pages. view
is the UI element that represents the whole page. In almost all cases, it is view
of UIViewController
. In init, it takes and initializes app
and asserts that view
exists.
Then, let’s write the operations. In the welcome page, there are a login button and a sign up button and we can move to the next page by tapping either button. We can implement each operation using the code below:
The main points of this pattern are:
- To make it reusable by defining each UI element with computed property to find the element when referencing it
- It defines properties for each UI element, referencing from
view
- Each operation method returns a Page. If it moves to another Page, you need to return that page object. If not, you need to return
self
.
Next, let’s take a look at the case where you assert the state of a page. In the sign up page, it checks whether the password which was entered is valid and the error message is shown. In this case, we need to add the computed property which returns the current state.
Conclusion
In this article, we covered:
- Abstracting a page is good
- Page contains operations and states of a page
- In the initializer, we need to assert whether UI elements exist
I have been bothered with the complication of UI testing for a long time. But, now I can read and write clean code, which follows DRY principle. If you like this idea, give it a try!
References:
- Introducing Page Object by Martin Fowler https://martinfowler.com/bliki/PageObject.html
- Introducing Page Object by Selenium https://www.seleniumhq.org/docs/06_test_design_considerations.jsp#page-object-design-pattern
- The practice of Page Object https://blog.getgauge.io/are-page-objects-anti-pattern-21b6e337880f