Swift GUI Testing with XCUI

iOS apps fail for a number of reasons other than simple logic errors that we typically catch with unit tests. The app may not install correctly, or there may be a problem when you move from landscape to portrait and back again. Your layout also might not work on one of the devices that you forgot to test it on. Or it might just hang if the network is down leaving the user with no option but to close the app.

It’s just not possible to test for these conditions using classic unit testing. If you remember the Agile Testing Pyramid, we need to be at higher up on the pyramid to catch these errors in the GUI, see Figure 1.

Agile Testing Pyramid

Figure 1: Agile Testing Pyramid

The bulk of your tests should be unit tests, these are small tests at the method level. GUI or UI tests are at the top of the pyramid and are harder to maintain. These are typically black box tests where each test creates a new session as we work through the GUI to get to the dialog that we’re trying to test. So UI tests by their very nature are brittle - small UI changes can break multiple UI tests - so not surprisingly there are less UI tests. But we still need to test the app end to end and not just its isolated components.

We’re going to have to use the XCUI framework to test our GUIs. There are a couple of other options out there but most of them have been abandoned or deprecated such as Frank a Cucumber derivative or Apple’s UIAutomation framework so XCUI seems to be the logical way to go. And if all else fails we can always go back to Calabash.

XCUI allows you to either record your interactions with the UI and then play them back or write the test code from scratch. Let’s take the easier route to begin with recording the UI interactions.

Recording Tests

Recording tests get you started using XCUI. I don’t think anyone would use it exclusively for testing as like all auto generated tools it can create so much extra garbage code. However it’s a great place to start getting your feet wet.

Download our Calculator app from github. Open with Xcode 8 and run the app. If everything is working correctly you should see the image in Figure 2.


Figure 2: Calculator App

To add XCUI testing to this or any other project take the following steps in Xcode :-
1. File->New->Target…
2. Scroll down to Test.
3. Choose UI Testing Bundle.
4. Click Next.
5. Click Finish.

If all goes well, you should see a CalculatorUITests folder and a CalculatorUITests.swift file similar to Figure 3.

XCUI template code

Figure 3: XCUI Template Code

The template code has 3 methods, setUp() and tearDown() as well as testExample(). Note also the highlighted red circular button on the bottom of the screen beside the blue breakpoint arrow. If you don’t see that then you’ve done something wrong in the steps above and you’ll need to try again.

To start recording put the cursor within the testExample() method and click the red button to start recording. Just try multiplying 3 times 4 and checking the answer in the results field, see Listing 1.

    func testExample() {
    // Use recording to get started writing UI tests.
    // Use XCTAssert and related functions to verify your tests produce the correct results.

    let app = XCUIApplication()
    app.otherElements.containing(.button, identifier:"7").children(matching: .textField).element.tap()


Listing 1: Autogenerated XCUI recorded code

XCUIApplication() creates the app in the Simulator. Then we tap the 3, *, 4 and equals button. XCUI loses the plot when we click on the results field. But we have enough to get us started. Recording makes a great starting point for tests but you will end up rewriting a lot of the code it produces.

XCUI uses the Accessibility framework, so make sure the text field has a name that it can reference. Click on the Main.storyboard and open the Identity Inspector tab. Choose the result field in the storyboard and call it resultsFld in the Identifier, see Figure 4.


Figure 4: Updating Accessibility Identifiers

Like our Unit Tests we want to Arrange-Act-Assert. We’re arranged or setup the objects, we’ve added the numbers together and now we need to assert that the resultsFld displays 12 when we multiply 3 * 4. Using XCTAssert we can assert that the value in the resultsFld is 12 as follows.

XCTAssert(app.textFields["resultsFld"].value! as! String == "12")

Updated testExample as shown in Listing 2 and run the test again. It should run successfully.

func testExample() {

    let app = XCUIApplication()

    let resultTextField = app.textFields["resultsFld"]
    XCTAssert(resultTextField.value! as! String == "12")


Listing 2: Updated recorded code

This is Part 4 of a series, the other blogs are below

Part 1 - Swift Unit Testing on Ubuntu
Part 2 - Swift Unit Testing in Xcode
Part 3 - SonarQube, Jenkins and Swift
Part 4 - Swift GUI Testing with XCUI
Part 5 - Mocking in Swift with Cuckoo