How to use UIAutomation to create iPhone UI tests | by James Turner

One of the more useful (from a developer standpoint) features coming in iOS 4 (formerly iPhone OS 4) is the UIAutomation tool. This lets you run an automated set of tests against an application, and test to see if they had the expected results. Unfortunately, at the time of this writing, there is minimal documentation for the tool, so here's a quick walkthrough of how to use it.

To start, you need the iOS 4 SDK, which is available as of today from Next, you need to make sure that you have your application set up to be easily run by the UIAutomation suite. The main thing is to tag all your UI controls in Interface Builder with names, by setting the Accessability label to a unique value for the view.

Attached Image

Once these are all set and you've rebuilt your application for debug, you need to write a Javascript file that runs your application and tests to make sure that everything is running as expected. Here's a sample file, followed by some commentary.

UIALogger.logStart("Starting Test");
var view = UIATarget.localTarget().frontMostApp().mainWindow().elements()[2];
var textfields = view.textFields();
if (textfields.length != 2) {
    UIALogger.logFail("Wrong number of text fields");
} else {
    UIALogger.logPass("Right number of text fields");
var passwordfields = view.secureTextFields();
if (passwordfields.length != 1) {
    UIALogger.logFail("Wrong number of password fields");
} else {
    UIALogger.logPass("Right number of password fields");
var errorVal = view.staticTexts()["error"].value();
if (errorVal != "Invalid User Name or Password") {
    UIALogger.logFail("Did Not Get Invalid Username Error: " + errorVal);
} else {
    UIALogger.logPass("Username Error Detected");

The first line of the test simply sends an informational message to the log. The next line uses UIATarget.localTarget().frontMostApp() to get the currently running application of the test target (which is whatever we've configured Instruments, the test runner, to run our tests on.) We then use mainWindow to get the main UIWindow, and then Elements to find all the children of the window. The third child of the main window in this application is a scroll view, so we use the [2] array reference to get it. We then get all the text fields (which don't include password fields), and make sure there are 2 of them. We also check that there is 1 password field. Next, we set the username and password field, and tap the submit button. Then we check to see that the error label has been set to the correct error message.

You should note that this last bit doesn't currently work. The text label string of a UILabel shows up as the StaticText field's name, not it's value, which is always nil. If you set the Accessibility label, it becomes the name property, and there is no longer any way to discover the current text in a UILabel. I have a bug report open with Apple about this.

You can find all the available Javascript objects by searching for "UI Automation Reference Collection" in the iPhone documentation online.

Once you've written your Javascript, it's time to run it and see if it works. Fire up Instruments (you can find it in Spotlight), and create an iPhone Simulator Automation trace:

Attached Image

Once you're in the Trace window, use the Choose Target pulldown to navigate to the debugging version of you App:

Attached Image

Use the Scripts pulldown to choose the Javascript test file you created, then click the record button. This will start up the iPhone simulator, wait about 5 seconds for your application to start, and then start going through the tests you wrote. Note that when the trace gets to the end of the Javascript file, it doesn't stop recording, you have to do it manually. You'll see the results in the Script Log:

Attached Image

You can also throw another instrument, such as the memory leak instrument, in with your UIAutomation run, and automatically find any memory leaks that occur while the application is being exercised.

One final tip. If you make a call to logElementTree() on any element, it will dump a full tree view of the current element and all its children to the log, which can be very useful when you're trying to figure out how to navigate the element tree.

Thanks to James Turner

Doron KatziPhone Dev