Architecting iOS XCUITests for iPhones and iPads

Shashikant Jagtap
YNAP Tech
Published in
4 min readMar 29, 2018

Apple’s XCUITest framework is a hot and emerging framework for UI automation of iOS apps and has gotten a lot of attention since it was launched at WWDC 2015.

XCUITest 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

XCUITest newbies should definitely watch 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 from 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. Using UIDevice API, we can get the current device running the test using the following code

if UIDevice.current.userInterfaceIdiom == .pad {// Do iPad Stuff }

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

XCUIDevice.shared().orientation = .landscapeRight

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 use the approach mentioned in this post. We will try to find the solution to 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

import XCTest
enum HomeScreen: String {
case guestButton = "Hello"
case registerButton = "Register"
case loginButton = "Login"
case welcomeText = "Welcome"
case introText = "Introduction to app"
var element: XCUIElement {
switch self {
case .guestButton, .registerButton, .loginButton :
return XCUIApplication().navigationsBars["XYZ"].buttons[self.rawValue]
case .welcomeText, .introText:
return XCUIApplication().staticTexts[self.rawValue]
}
}
}

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

import XCTest
enum HomeScreen: String {
case guestButton = "Hello"
case registerButton = "Register"
case loginButton = "Login"
case welcomeText = "Welcome"
case introText = "Introduction to app"
var element: XCUIElement {
switch self {
case .guestButton, .registerButton, .loginButton :
if UIDevice.current.userInterfaceIdiom == .pad {
return XCUIApplication().tabBars["XYZ"].buttons[self.rawValue]
} else {
return XCUIApplication().navigationsBars["XYZ"].buttons[self.rawValue]
}
case .welcomeText, .introText:
return XCUIApplication().staticTexts[self.rawValue]
}
}
}

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 a better approach let me know, always happy to learn.

Original Blog Post Here

--

--

Shashikant Jagtap
YNAP Tech

All the posts published on this channel before I joined Apple. Thanks for being a reader of XCBlog. Web: shashikantjatap.net, xcteq.co.uk