Page Objects - novoda/android-demos GitHub Wiki

What is the Page Object Pattern?

The Page Object Pattern is a well known and often used pattern in automation, also known as Testing Robots Pattern. It is used to create an abstract domain-specific language (DSL) for interacting with Objects in your different views. The Page Objects don't necessarily have to cover all elements on one page; it could be that you split one view into multiple Objects to keep them small and simple.

Architecture Diagram

Why do we use it?

It's a simple way to create reusable components representing the application under test. Apart from reusability, it actively increases the readability of your checks. The tester usually names the methods in those classes with the domain driven language which provides better understanding for new people joining the project.

Due to the high reusability and the focus on the single responsibility principle, the whole framework becomes easier to maintain. The idea is that the Page Objects and the UI components the Page Objects consist of are the only places which the engineer adapts if there are changes in the different views of the application. These components (for example StandardDialogFragment in the above diagram) can then be reused throughout our implementations.

Using Page Objects can also help keep our tests performant and reliable by eliminating the need for explicit waits. Rather than blindly waiting for a fixed amount of time we can utilise our framework’s own mechanism. Espresso’s ViewInteraction for example means that we don’t have to worry about handling any work happening on the UI thread. If our app requires asynchronous/reactive sequencing we’ll need to implement it ourselves. You can also read more about Espresso with RxJava. Of course we could use implicit waits without Page Objects but since our code will probably get messier by doing so, it’s likely that “quick hacks” will start appearing.

Importantly, we see Page Objects as an abstraction that allows our tests to run based on the same information that our user will see. A real user will press a button once it appears without knowing the ID or any other implementation detail.

Page Object layout

The general idea of creating a layout for the classes is to split it into two or three parts - depending if there are reusable components like a menu included in the view.

The first part consists of the Identifiers of the application. The engineer creates a set of fields containing the driver specific information on how to access Objects on the view. A non-exhaustive list of those identifiers is ViewInteractions for Espresso, XCUIElements for XCUITest, and MobileElements for Appium.

Login Screen Example 1 Login Screen Example 2 Login Screen Example 3

There are many ways to access these elements, and there is depending on the framework a clear hierarchy of the ways. It is considered a good practice to use the ID's provided by the developers as the first approach to take and even demand those from the developers if they don't exist because they are the most failsafe way to address elements in the Mobile application. If this is not possible - due to implementation details or the nature of the items the next step would be creating a new class which matches those. An excellent example of those are List- and Recyclerviews in Android which need to have a BoundedMatcher to address specific items in their structure.

Matcher Example 1 Matcher Example 2

In some cases multiple UI elements use the same ID, or a component might appear multiple times on a screen. When this happens we’ll need to be more specific by adding another matcher. For example multiple elements that share the same ID might have different text labels so we could use those in conjunction with the ID matchers we already have.

Assertions

There are 2 schools of thought when it comes to the relation between Assertions and Page Objects. For many these are 2 separate entities with different responsibilities and should therefore exist as separate classes that don’t know about each other, with the test itself being responsible for orchestrating the Page Object actions and the Assertion execution.

What we have seen in practice however is that in fact there are shared concerns and common information between the 2. Both need to know about the UI elements (Page Objects interact with them, Assertions validate their existence or lack of). Thus by keeping everything in one place we avoid duplication. It’s also worth noting that including Assertions within Page Objects better encapsulates the knowledge of the UI. Otherwise we need to expose information about the UI within the test and pass that on to an Assertion.

Finally, there’s another angle from which to view the question. Remember what we said before about Page Objects as an abstraction. Let’s now extend this thinking to asserting: It is the same user interacting with our application who will “validate” what they see on the screen. The abilities to interact and to assert belong to the same entity.

Dependency Structure

In the above examples our Page Objects only depend on matchers. Just like the actual Views in the application we want to keep them isolated from each other. To handle transitions between Views we implement Flows, which depend on Page Objects and not vice-versa. We can also use Dependency Injection to better separate responsibilities.