June 21, 2015
In Xcode 7, automated UI Testing was finally integrated into the IDE to allow developers to seemlessly run integration testing on top of unit testing. Thankfully, this was also introduced in a standard development language (Swift) as opposed to the prior JavaScript implementation. Today I’m going to walk through how this new Xcode feature works and how to utilize it.
How it Works
Some may remember that an Xcode Instrument called UI Automation has enabled this type of testing for years using JavaScript tests. However, despite the differing languages of the UI Automation Instrument (JavaScript) and Xcode UI Testing (Swift) the underlying technology remains the same using the Accessibility layer to navigate, select and simulate touch on the view hierarchy. I go into
how they differ and limitations in another article, but fundamentally all you need to know is that UI Testing uses Accessibility elements which mimic the UIElements in your view hierarchy.
Writing the First Test
Each new iOS Application comes with an option to create the app with UI Tests.
To start, create a new tab-bar application and open the UIAutomation Test file in your IDE. First, ensure your app is launched in the setup method:
override func setUp() {
super.setUp()
continueAfterFailure = false
XCUIApplication().launch()
}
… and then create a function that starts with the word test and access the application variable.
func testAButtonTap() {
let app = XCUIApplication()
...
}
From here you can create a line of code navigating the view hierarchy and callingactions (tap, input text, etc.) on view elements like so:
app.tabBars.buttons["Second"].tap()
However, crafting these commands by hand is pretty time consuming for a custom app. Instead I’d suggest starting every test you author by using the UI Testing record functionality and auto-generate this starter code. You can find this record button in the bottom bar:

Alright, so we can write a test, but how do we write good tests and what is a good test?
Write a Good Test
There are several approaches to UI testing, but I’ll highlight two main categories: exploratory and state-checking. Exploratory testing is great for investigating crashes from unexpected permutations of user state. However, to test for regressions, dead-end flow or valid UI-state your going to need more than just tapping on the screen.To accomplish these goals you will need to validate UI state using assertions just like in unit testing. A simple example is a feature where tapping a button changes its label text. Add a label to the view and change its text once the user presses a button. I you need help you can check out the accompanying GitHub example.Next, create a new test function, press record and tap the app’s button to create starter code for this function. It should look something like this:
let app = XCUIApplication()
app.buttons["Press Me"].tap()
app.buttons["I was pressed"].tap()
However, this code just taps on the item instead of reading its value. What we need to do first is check the initial state of the label so if our test fails we know whether it started from an expected state or not.
XCTAssert(app.buttons["Press Me"] == "Press Me")
… but wait, this is a self-afirming statement! To test this state legitimately we’ll have to access this button another way. Accessing the button via the view hierarchy is one such approach:
let unselectedText = "Press Me"
XCTAssert(app.buttons.elementAtIndex(0).label == unselectedText)
app.buttons.elementAtIndex(0).tap()
XCTAssert(app.buttons.elementAtIndex(0).label == "I was pressed")
app.buttons.elementAtIndex(0).tap()
XCTAssert(app.buttons.elementAtIndex(0).label == unselectedText)
This is a great example of how to make your tests more robust by accessing element using a query that is the least likely to change over time. For example, if we expect these text to change over time we can either use the selected / unselected state as the assertion or compare against the same strings we use to set the button.
Benefits of UI Testing
When deciding what to test think of the general flows through your applications that contain state at a higher granularity than unit testing and are unlikely to change greatly in their UI. For example, Automating UI testing is great way to ensure that you don’t introduce regressions through development. Lastly, another great benefit of UI Testing is that since it utilizes the Accessibility Layer it helps guarantee your app is accessible for those using iOS with accessibility settings turned on.
This is Part 1 of a 3-part series on Xcode UI Testing…
Read Part 2: Xcode UI Testing vs. The UI Automation Instrument
Read Part 3: Advanced UI Testing: Strategies, Hidden Gems and Limitations
Related