Introduction
This is a beginner level article. I hope after going through it, a typical iPhone developer would be able to perform automated UI testing.
Background
UI Automation testing is an important value addition in iOS4. It is supported by a new instrument object called “Automation”. It’s quite suitable for UI testing of Productivity style applications.
Automation instrument works from scripts (written in JavaScript). It simulates/fires required events on target Application. Test script must be a valid executable JavaScript file accessible to the instrument on the host computer.
What is a Test Script?
Test script is an ordered set of commands, each of which accesses a user interface element in application to perform a user action on it or to use the information associated within it.
In this article, I will explain UI Automation testing with the help of one sample application developed using Coco Touch framework.
Description
My sample application has one screen called “Login”. It contains two text fields name as “User name” and “Password” and one Button called “Login”.
Before writing the test script, tag all your UI controls in “Interface Builder” with names, by setting the Accessibility label to a unique value for the view (It is a mandatory requirement).
Now compile your application in debug mode.
Test Scripts
As I mentioned above, test scripts are basically a set of ordered commends. In other words, it’s conversion of textual test cases into JavaScript which would be auto executed by “Automation” instrument.
Here is the sample test script:
var window = UIATarget.localTarget().frontMostApp().mainWindow();
var view = window.elements()[0];
var textfields = window.textFields();
var passwordfields = window.secureTextFields();
var buttons = window.buttons();
var textviews = window.textViews();
var statictexts = window.staticTexts();
var target = UIATarget.localTarget();
if(textfields.length!=1)
{
UIALogger.logFail("FAIL: Inavlid number of Text field(s)");
}
else
{
UIALogger.logPass("PASS: Correct number of Text field(s)");
}
if(passwordfields.length!=1)
{
UIALogger.logFail("FAIL: Inavlid number of Secure field(s)");
}
else
{
UIALogger.logPass("PASS: Correct number of Secure field(s)");
}
if(statictexts.length!=2)
{
UIALogger.logFail("FAIL: Inavlid number of static field(s)");
}
else
{
UIALogger.logPass("PASS: Correct number of static field(s)");
}
if(buttons.length!=1)
{
UIALogger.logFail("FAIL: Inavlid number of button(s)");
}
else
{
UIALogger.logPass("PASS: Correct number of button(s)");
}
if(textfields["username"]==null || textfields["username"].toString() ==
"[object UIAElementNil]")
{
UIALogger.logFail("FAIL:Desired textfield not found.");
}
else
{
UIALogger.logPass("PASS: Desired UITextField is available");
}
if(passwordfields[0]==null || passwordfields[0].toString() == "[object UIAElementNil]")
{
UIALogger.logFail("FAIL:Desired UISecureField not found.");
}
else
{
UIALogger.logPass("PASS: Desired UISecureField is available");
}
if(buttons["logon"]==null || buttons["logon"].toString() == "[object UIAElementNil]")
{
UIALogger.logFail("FAIL:Desired UIButton not found.");
}
else
{
UIALogger.logPass("PASS: Desired UIButton is available");
}
textfields["username"].setValue("");
passwordfields[0].setValue("password");
buttons["logon"].tap();
var errorVal=textviews["error"].value();
if(errorVal!="Invalid User Name or Password")
{
UIALogger.logFail("Did Not Get Missing UserName Error : "+errorVal);
}
else
{
UIALogger.logPass("Missing User Name");
}
textfields["username"].setValue("username");
passwordfields[0].setValue("");
buttons["logon"].tap();
target.delay(2);
var errorVal=textviews["error"].value();
if(errorVal!="Invalid User Name or Password")
{
UIALogger.logFail("Did Not Get Missing Password Error : "+errorVal);
}
else
{
UIALogger.logPass(" Missing Password");
}
textfields["username"].setValue("username");
passwordfields[0].setValue("password");
buttons["logon"].tap();
target.delay(2);
All UI elements in the application are represented to the script through an ordered hierarchy of objects defined by the UIAElements
class and its subclasses like UIATarget
, UIALogger
, etc.
For more information, refer to the UI Automation Reference Collection available at Apple Developer site.
After completing the script, we’re all set for execution. Here are the steps:
Step 1
Open Instruments (You can find it is Spotlight). Select “Automation” from template selection window.
Step 2
It will open Trace Window. Here, you have to select debugging version of your application with the help of “Choose Target” pull down.
Step 3
Use “Script” pull down to select test script file and then click on “Run and Record” button.
It will auto launch “iPhone Simulator” and start executing the test scripts (this operation might take 4-5 seconds).
Reusable Test Scripts
The API offers a #import
directive that allows you to write smaller, reusable discrete test scripts.
E.g. If you were to define commonly used functions in a file named TestUtilities.js, you could make those functions available for use in your test script TestXYZ.js by including in that script the line:
#import "<path-to-library-folder>/TestUtilities.js"
Hardware Requirement to Try Out the Attached Sample Code
Mac Mini (Intel processor based) with Snow Leopard 10.6 (or above) and iOS SDK 4.0:
- Unzip attached “LoginWindow_src.zip”, compile it in debug mode and test it on Simulator.
- “username/password” are valid credentials; enter these values in corresponding “user ID” and “Password” field.
Are You Facing "Unexpected error ...." ?
"Unexpected error in -[UIATarget_0x5a20d20 frontMostApp],
/SourceCache/UIAutomation_Sim/UIAutomation-37/Framework/UIATargetElements.m line 437"
If you are facing this problem, this can be corrected by copying a com.apple.Accessibility.plist
to 4.0.1.
Copy com.apple.Accessibility.plist
to:
~/Library/Application Support/iPhone Simulator/4.0.1/Library/Preferences
Make sure that there should be only two Keys in this file name as “AccessibilityEnabled
” and “ApplicationAccessibilityEnabled
”. Both the keys should be checked.