Architecting iOS XCUITests for iPhones and iPads

Apple’s XCUITest framework is a hot and emerging framework for UI automation of iOS apps. Since launched in WWDC 2015, it got a lot of attention and enhancement. It allows us to write UI tests for iOS apps in Swift which makes it easy for iOS developers to add UI tests for the iOS applications for both iPhone and iPads. It’s essential to consider both iPhone and iPads for XCUITests as users using apps on iPads can’t be ignored. With XCUITest, continuous integration and continuous delivery became painless as unit and UI tests are written using the same framework i.e XCTest. That was not the case before the XCUITest, the tools like Appium, Calabash allowed to write UI tests using other languages like Ruby or Java which became the pain for CI/CD and flow of iOS development. XCUITest can be written for iOS apps however, iOS devices have different variants e.g iPads with different screen sizes and iPhone with different screen sizes. We have to make sure XCUITests should run flawlessly on all variants without causing a lot of duplication. If the XCUITest is architected properly then we can avoid duplications of code and still able to run all our XCUITest on different variations. In this post, we will cover how to architect XCUITest for both iPhone and iPad.

XCUITest

The newbie of XCUITest should definitely this WWDC video in order to understand the basic functionality of XCUITest framework. XCUITest allows us to write tests for iOS apps using Apple’s own programming language Swift. It’s way different than other third-party frameworks like Appium, Calabash etc. If you want to compare XCUITest with Appium then read this post to get the better understanding of each framework. If you want to know the hands-on exploration of all the new XCUITest feature, then please refer my previous blog post on New XCUITest Features with Xcode 9 where I have covered almost all the features with detailed examples. You can setup Protocol Oriented architecture for XCUITests as mentioned in this post on DZone and second part is available here. We can make XCUITest scalable bu using some of the techniques mentioned in WWDC 2017 talk on talk on engineering for testability which focuses on testable code.

UIDevice and XCUIDevice

Apple has provided UIDevice class to get the representation of the current device and XCUIDevice class to simulate physical buttons and device orientations. This makes architecting tests on iPhone and iPads so easy if we have organized XCUIElements properly. By Using UIDevice  API,  we can get the current device running the test using following code

WithXCUIDevice, we can set device orientation to landscape or portrait using following code

These two APIs will be super useful to set our XCUITests on both iPhones and iPads.

Avoid Two Suites

In many projects, I saw that people create two separate test suites for iPhones and iPads. There are two separate Xcode schemes executing the tests in iPads and iPhone. There is also conditional execution all over the tests which is brittle to manage test suites. We don’t need to do this as if we can use approach mentioned in this post. We will try to find the solution for these problems later in the post.

Organising XCUIElements

While architecting XCUITests on iPad and iPhones, it’s very important to organize XCUIElements in the proper format. I strongly recommend using Swift enumerations for organizing elements on screens. Please refer this post to the protocol-oriented architecture of XCUITest. In my recent post on Organising XCUIElement with Swift enumeration, I have explained how to organize elements as per the screen. Let’s imagine that our iOS app has a home screen which contains three buttons and two static texts. We can write enum like this

we have assigned the string values to enum cases and grouped the cases as buttons and static texts.

Conditional XCUIElements on iPad

The enum mentioned above will work perfectly for the iPhone as all the buttons are part of the navigation bar. However, if we have a situation wherein iPad designs all the buttons are in the Tab bar. The approach mentioned in the enum will not work for iPad. However, by using UIDevice, we can conditionally return XCUIElement from the above enum if the device is iPad as shown below

Now that, enum will return the buttons from tab bars for iPad and navigation bar for iPhone. We don’t have to touch our actual test implementation from where these XCUIElements will be accessed. Using this approach we can avoid a lot of duplication of the code as well as makes our test suite accessible for all device variant and orientations.

Conclusion

With the use of the protocol-oriented architecture of XCUITest, Swift enumeration and UIDevice API from Apple, we can achieve UI automation on iPhone and iPad devices without repeating to code. There is no need to create separate schemes or adding conditions everywhere in the test code for iPad scenarios. Hope you like this approach for architecting tests for both iPhones and iPads. What you think about this approach, if you think of better approach let me know, happy to learn.