Getting Started With Automated UI Testing For iOS

UIAutomation basics

The UI Automation API has been part of the iOS SDK since version 4.0. It supports running automated tests in Instruments using Javascript.

If your app already has accessibility/VoiceOver support, I have some good news: UI Automation uses the UIAccessibility protocol to trigger events.

Getting Started

There are basically 2 ways to create a test script. You either record a test scenario or you program it manually. This post concentrates on the programming option. I will use Apple’s sample SimpleDrillDown sample app as a starting point.

Open the SimpleDrillDown project in XCode. The start screen of the app looks like this:

screenshot of simple drop down

In order for the UI elements to be easily accessible from Javascript, we use the accessibilityLabel property to give them a meaningful name.

RootViewController.m:

DetailViewController.m:

Select Profile from the build button to launch Instruments and select the Automation template

screenshot of selecting instruments (profile)

Immediately stop the recording. Create a new test script by clicking on the Add button in the Scripts panel and select “Create…” from the popup menu.

screenshot of select create from add script menu

Name the script whatever you want by double clicking on its name. In the Script editor right click on the main panel to export the script (preferably to a location inside the Xcode project folder structure).

To get a feeling with the different UI elements that are available, logElementTree() is your best friend. Paste the following code in the Script editor:

When you run the script (⌘R) the trace log contains the following output:

screenshot of initial tracelog

As expected, the table view name is “RootTable”. This makes it easy to access the table in Javascript. We have enough info to add some checks to the script:

To avoid duplication of the same test code over and over again, it’s best to add a helper function to the script.
The test script now looks like this:

If you run the test script again, you have a basic automated UI test. It’s that easy!

Simulate gestures

The next part of the test selects a play and checks if the detail table is correctly shown.
Simulating a tap on e.g. the “Othello” row is just one line of code:

Then wait 1 second for the animation to be finished before checking the detail table groups/rows:

After the delay add some more checks. The extended test function should now looks like this:

If you want to simulate other gestures than just a simple tap, take a look at the following functions:
touchAndHold(), doubleTap(), twoFingerTap(), tapWithOptions(), dragInsideWithOptions(), flickInsideWithOptions() and scrollToVisible().

Simulate typing

Another common action in an iOS app, is typing text in a UITextField. It’s easy to set the value of the UITextField with the setValue() function, but that doesn’t generate any keyboard events. Simulating typing on the keyboard used to be pretty complicated, but since iOS 5.0 a new function was introduced: typeString().

To simulate a real life situation where a user actually uses the keyboard to type, you need something like this:

Other tidbits & advice

With the above script sample code, you can already test quite a lot of the functionality of most iOS apps. However it’s worth mentioning that other user actions are also pretty easy to simulate.

Rotate the device:

Send an app to the background and return after a delay:

target.deactivateAppForDuration(10);

Don’t forget to put delays in your test code whenever an animation occurs or when the app downloads data from e.g. a web service:

target.delay(1);

When you’re stuck writing your test, remember that logElementTree() and logElement() are your best friends. These functions are available for all UI elements, so you don’t always have to log the complete main window tree.

While writing your tests, keep in mind that you’ll have to maintain them as your app evolves over time. Your test code deserves as much attention as your app code:

  • Split your test code in logical test functions
  • Use helper functions to avoid writing the same test code over and over again
  • Use comments whenever needed

Personally, I always run my tests on a real device, preferably the least performant one I have. That’s usually also the device that generates memory warnings more often than when you run the tests on the latest and greatest device.

It’s a good habit to run UI tests regularly when you make changes to your app. That way you’ll detect bugs shortly after you made the change that causes the bug.

The UI tests for my PhotoMeta app require 20 minutes to run (on a first generation iPad) and I run them at least twice a day. Once during lunch and once in the evening.

Useful links

UI Automation Reference
UIAElement Class Reference

About the Author:


Photo of Chris Cornelis

Chris Cornelis

Chris is a software engineer with over 20 years of experience encompassing many different technologies. His projects have included a traffic simulation tool, database middleware, a front-end tool for digital presses, a container terminal management system and a SaaS platform for personalised marketing.

In 2008, when the App Store launched, he founded Galarina. Galarina specializes in the development of unique and useful photography related solutions for the iOS platform with 5 apps in the App Store. Chris is also a freelance iOS engineer currently pushing the Everest app to new heights.

Twitter: @GalarinaDev
Website: Chris’s Website