Learning UITesting using Xcode
Let me demystify this essential tool to testing your Apps
IO tests allow direct interaction with the App, with the simulator providing simulated touches and swipes with the App. This is opposed to the use of Unit testing. While Unit testing is great — you split up different sections of the App and then test them — it does not provide a wholistic view of how the App is behaving.
Luckily, Xcode is shipped with a UITesting framework built right in.
Prerequisites:
- Some understanding of testing using Xcode
Terminology
UITesting: The process of testing the User Interface (UI) for Xcode apps
XCUIElement: A UI element in an application, that provides interactions with the UI like tapping, pressing, swiping, pinching and rotation
XCUIApplication: A proxy for an application that can be launched and terminated
XCUITest: An automation framework that ships with Xcode
XCTest: A framework that allows iOS developers to create and run unit, performance and UITests for Xcode projects
The project
I’ve got a project that I’ve used in a post about animations on UIPageView (https://medium.com/@stevenpcurtis.sc/an-animated-uipagecontrol-from-scra-75bc919d3174).
There are several was that the page can be scrolled — either through gestures or pressing the inviting looking next button on the screen.
So how can this project be tested?
The title of this article should be a clue — Unit tests are not really the way to go with this project.

The standard UITests setup
UITests can be rather demanding, so you probably want continueAfterFailure to be set to false, which means that execution will stop if there is a failure.
The App is set up as an XCUIApplication() and then can be launched.
UI Recording
At the bottom of the screen there is a very primising looking recording button. This becomes available when you create a test function with any applicable name in the UITests, for example
func testSwipes() {}
and place the cursor just between the curly braces to enable the record function for that particular test

This can be pressed, and it records the actions you do.
I swiped a couple of times, and the following code was generated:
We can then make assertions through XCTAssertTrue statements
Something like
XCTAssert(app.staticTexts[“Use your device microphone to say the color displayed”].exists)
(lots of these rather basic functions are avaliable here: https://kapeli.com/cheat_sheets/Xcode_UI_Testing.docset/Contents/Resources/Documents/index )
Issues?
At times I came across the following error:

Occasionally restarting the simulator helped with this, but on other occasions this is not true and we need to resort to other skills as detailed below:
Finding XCUIElements using staticTexts
We can manually find the pageIndicator, and then check that a button exists on the screen (after the indicator has been tapped) that has “Learn” written on it.
However this approach is extremely fragile. What if the target text changes at some point (answer: Our UITest would also fail)
Finding XCUIElements using Accessibility Identifiers
These can be set through the storyboard

However in my case I am reusing the same component through multiple instances of the view (look at the code if this does not make sense to you).
I set my particular accessibilityIdentifier through viewDidLoad
Now the issue may be that with larger Apps that you do know know which accessibilityIdentifier you set. No problem — just use the Accessibility Inspector.
Using the Accessibility Inspector
This is rather a great tool.
Right-click on the Xcode icon and select Open Developer Tool> Accessibility Inspector.

Inside the Accessibility inspector choose your device or simulator

You can then use the inspection pointer which looks rather like a target in Accessibility Inspector

Now, running the App as usual lets you identify individual elements on the screen

Which in turn gives you the ability to see the identifier! In this case, the identifier is “Learn”

Waiting for transitions
You may have noticed above
.waitForExistence()
gave us the ability to wait for a transition to finish.
The details
Tapping a button
app.buttons["add"].tap()
Typing text
textField.typeText("hello")
Providing (of course) that you have identified and selected the textfield first with
app.textFields["input"]
app.tap*(
Dismissing alerts
app.alerts["Alert Title"].buttons["title"].tap()
Using sliders
app.sliders.element.adjustToNormalizedSliderPosition(0.5)
Using Pickers
app.adjustToPickerWheelValue("first value")
where the picker has first been identified with
let firstPickerPredicate = NSPredicate(format: "label BEGINSWITH 'First Picker'")
let firstPicker = app.pickerWheels.elementMatchingPredicate(firstPredicate)
Pull to refresh
Select the cell
let cell = app.staticTexts["AA"]
then choose the vector in which to drag
let start = cell.coordinateWithNormalizedOffset(CGVectorMake(0, 0))
let end = cell.coordinateWithNormalizedOffset(CGVectorMake(0, 6))
start.pressForDuration(0, thenDragToCoordinate: finish)
Detect whether a view controller is on top of the navigation stack
XCTAssert(app.navigationBars["Title"].exists)
The full repo link:
https://github.com/stevencurtis/SwiftCoding/tree/master/UITestswithXcode
Want to get in contact? Try the link here: