Using the Page Object Model for structured and readable UI tests

30. November 2016 blog 0

When we started rebuilding our apps, we decided to focus heavily on stability and testing. Our old app has quite a few crashes in it and we believe the only way to prevent such error-prone apps is to put a lot of emphasis on testing from the start. In Xcode 7 Apple gave developers the opportunity to easily write UI tests. These are tests that automatically run through the interface of your app to test specific screens or components.

Once we started writing these kinds of tests it became apparent that although the tools Apple gave us were very easy to use, they weren’t leading to nicely structured and easily readable tests. Take this simple 1-action test for example:

Looks simple enough right? The application opens up and we tap a button with the text “Search”. This would work well for a single test that has to tap this button. However if there are a lot of tests that use this button this hardcoded “Search” string becomes a problem. What if we decide to rename this button? All the tests would fail and we would have to spend some time to rename all the individual references to the “Search” button. It sure would be nice if there was only one reference to this button that our tests could use.

Enter Page Objects

To solve this problem (and many others at the same time) we used a pattern called the Page Object Model. Page Objects are helper classes that wrap all the actions within a single screen. Let’s look at an example:

With this Page Object, we can now write our test like this:

Now our test clearly describes the intended action to be performed.

Chaining

The test we wrote now only contains 1 action: clicking a button. More often than not, a UI test contains multiple actions that test an entire flow within the app. In the traditional way of writing or recording UI tests, this flow will become hard to read. Take for instance this more elaborate test:

We still click the “Search” button and that wil still open the search screen. However, we have no idea that this is actually happing. The result of tapping the button is unclear. On line 4, we assume we can click a button called “Order Descending” but what screen this is on and if this is even possible on the currently visible screen remains to be seen. It would be nice if these assumptions are set in stone so the person writing tests knows exactly what the result is of each action. Once again Page Objects can help us with that:

What did we do here?

  • We created a new Page Object class called “SearchScreenPageObject” that defines the actions we can perform on this screen (tapping a button and executing a search)
  • We made our previously created function “openSearchScreen” return an instance of this new SearchScreenPageObject.

Because the “openSearchScreen” function now returns a specific type of Page Object. We can now write our test like this:

Summary

By implementing our UI tests with the Page Object Model we cleaned up our code a lot and made our tests more readable. As an added benefit, it is now impossible to write a testflow that is not compatible with our app. This allows us to spend more time thinking about the flow of a test and less about the technical implementation of the test.