Sharing Page Object classes and Test scenarios between Android and iOS

How we merged iOS and Android Page Objects classes and Test scenarios

Alona
Property Finder Engineering and Tech Blog

--

Hello “Bug Hunters” and everyone keen to learn more about how we can fight the good fight in QA!

At Property Finder we pay a lot of attention to the automation part of testing so having best practices in our development process is a must. While implementing our tests for a mobile project we faced a few issues that needed to be improved.

Originally we had separate classes for iOS and Android; we literally had the same code duplicated for iOS and Android page objects methods and tests. It’s not exactly ‘wrong’ to use it this way but we found it to be a bit complex, especially when we have five different apps to automate: it certainly would confuse future test maintenance, and make parallel testing difficult. Also, when it comes to best practices in code quality, duplicating the same code is not the best approach and since IOS & Android UI and functionality of app’s are similar we decided to improve our framework by having methods that allow us to use same Page Object classes and Test scenarios for both — iOS and Android — together.

Here’s how we did it

We are using mostly same test cases, methods and functionality between Android and iOS in our apps, so the main difference is to identify the objects on the page. That is why we defined both platforms object identifiers in the common page.

1. Created a method that picks the right selector based on the platform using default types

We needed a method that would choose the right selector to use while running the test. By having the following selector structure:

element :selector, ‘<android selector>’ , ‘ <ios selector>’

We implemented a method as follows:

2. Native methods override

Since we are using Site Prism for our page objects to make all of the above work — native Site Prism methods located in DSL module had to be overridden:

3. How it looks on Page Object class

With the default selector type it looks like:

element :selector_label, 'android label' , 'name == "ios label"'

With the non-default selector it looks like (For Android we have class: selector type and for iOS — xpath://) :

element :button,'class:android.widget.ImageButton',''xpath://XCUIElementTypeStaticText[@name="Section']

As previously mentioned in section 1 — we can also have a selector only for Android or only for iOS — it will still work and use it based on the platform.

elements :platform_specific_element, 'android_button_selector'

4. Identified default selector

We implemented a “Base Page” that all other page classes inherit. Instead of having method for a selector type that might not even get used, we defined a default selector type. In our apps most elements have the types ‘predicate’ for iOS and ‘id’ for Android so we set it as a default in methods:

5. Created a variable for default type in Android and iOS

Instead of mentioning it in the method we created a variable with a default selector type per platform:

And changed the class variable:

Benefits we have got:

  1. Easier maintenance
  • if a selector is changed, added or removed you just go to same Page Object and change it for both
  • if the test logic is changed you just make a change in the same class without jumping through folders between Android and iOS

2. Time saved on test implementation

  • instead of duplicating the same code for each platform we only have to write one class
  • keeping logic and test cases common for both platforms
  • having customized methods allows us to not mention the common (default) selector type when identifying selectors

3. Instead of keeping everything separate we now have the following structure:

AppName
|->pages
| |->BasePage.rb
| |->page1.rb
| |->page2.rb
|->features
| |->test1.rb
| |->test2.rb

Instead of

AppName
|->Android
| |->pages
| | |->page1.rb
| | |->page2.rb
| |->features
| | |->test1.rb
| | |->test2.rb
|->iOS
| |->pages
| | |->page1.rb
| | |->page2.rb
| |->features
| | |->test1.rb
| | |->test2.rb

Which is a lot easier to handle!

You can find BasePage.rb here

That is it! Thanks for reading

If you liked this article and want to be part of our brilliant team of engineers that produced it, then have a look at our latest vacancies here.

--

--