在iOS4中实现UI自动测试

简介

这篇文章的对象是 iOS 4 的初学者,我希望一个典型的iPhone 开发者能够通过这篇文章掌握自动设置UI测试的方法。

背景

UI 自动测试iOS 4中重要的附加功能,它由名为“Automation”的新的工具对象支持,非常适合Producitivity风格应用的UI测试。

Automation工具从脚本工作(用JavaScript语言编写),它在应用上模仿/击发被请求的事件。测试脚本必须是可靠的可执行JavaScript文件,而且该文件可获取主机的工具。

什么是测试脚本?

测试脚本是有顺序的命令集合,每一个命令获取一个应用中的用户接口组件,然后在上面执行一个用户行为,或者使用与之相关的信息。

描述

我使用的应用例子有一个名为“登陆”的屏幕,包含两个文本域名:分别是“用户名”和“密码”,以及一个“登陆”按钮。

写测试脚本之前,在“Interface Builder”中标记所有的UI控制,在视图中将可存取性标签设置成一个唯一值(必须)。

在调试模式中编译你的应用

测试脚本:

正如我上面提到的,测试脚本基本上是有顺序的命令集合。换言之,它将文本测试的例子转换成可以被“Automation”工具自动执行的JavaScript

下面是测试脚本的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Get the handle of applications main window
var window = UIATarget.localTarget().frontMostApp().mainWindow(); 
 
// Get the handle of view
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(); 
 
// Check number of Text field(s)
if(textfields.length!=1)
{
   UIALogger.logFail("FAIL: Inavlid number of Text field(s)");
}
else
{
   UIALogger.logPass("PASS: Correct number of Text field(s)");
}
// Check number of Secure 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)");
} 
 
// Check number of static 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)");
} 
 
// Check number of buttons(s)
if(buttons.length!=1)
{
   UIALogger.logFail("FAIL: Inavlid number of button(s)");
}
else
{
   UIALogger.logPass("PASS: Correct number of button(s)");
} 
 
//TESTCASE_001 : Test Log on Screen
//Check existence of desired TextField On UIScreen
if(textfields["username"]==null || textfields["username"].toString() == "[object UIAElementNil]")
{
   UIALogger.logFail("FAIL:Desired textfield not found.");
}
else
{
   UIALogger.logPass("PASS: Desired UITextField is available");
} 
 
//TESTCASE_1.2 :Check existence desired of PasswordField On UIScreen
if(passwordfields[0]==null || passwordfields[0].toString() == "[object UIAElementNil]")
{
   UIALogger.logFail("FAIL:Desired UISecureField not found.");
}
else
{
   UIALogger.logPass("PASS: Desired UISecureField is available");
} 
 
//TESTCASE_1.3 :Check For Existence of Buttons On UIScreen
if(buttons["logon"]==null || buttons["logon"].toString() == "[object UIAElementNil]")
{
   UIALogger.logFail("FAIL:Desired UIButton not found.");
}
else
{
   UIALogger.logPass("PASS: Desired UIButton is available");
} 
 
//TESTCASE_001 : Missing User Name
/////////////////////////////////////// 
 
textfields["username"].setValue("");
passwordfields[0].setValue("password");
buttons["logon"].tap(); 
 
//target.delay(2); 
 
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");
} 
 
//TESTCASE_002 : Missing Password
//////////////////////////////////////////////// 
 
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");
} 
 
//TESTCASE_003 : Successful Log On
textfields["username"].setValue("username");
passwordfields[0].setValue("password");
buttons["logon"].tap();
target.delay(2);

应用中的所有UI组件通过有次序的对象层级结构传达给脚本,该层次结构通过UIAElements类定义,包括UIATargetUIALogger等子类。

请参照苹果开发者网站的UI Automation Reference Collection获取更多信息。

完成脚本之后按下列步骤执行。

第一步

打开Instruments(你可以在Spotlight中找到它),在样本选择窗口中选择“Automation”

第二步

Trace窗口会打开,在“Choose Target”下拉窗口的帮助下选择应用的调试版本。

第三步

使用“Script”下拉窗口选择测试脚本文件,然后点击“Run and Record”按钮。

之后会自动运行“iPhone Simulator”,并开始执行测试脚本(可能花费4-5秒时间)。

可重用的测试脚本

API提供一个#import指令,你可以用它编写更小的、可重用的、分离的测试脚本。

例如:如果你准备在文件 TestUtilities.js中定义常用函数,你可以在脚本中加入命令行 #import”<path-to-library-folder>/TestUtilities.js”,从而使你的测试脚本能够使用这些函数。

测试样本代码的硬件要求

带有 Snow Leopard 10.6(或者更高版本)和iOS SDK 4.0 的Mac Mini(Intel处理器版本)

(1)解压附件“LoginWindow_src.zip”,在调试模式下编译它,并在模拟器Simulator上进行测试。

(2)“用户名/密码”是可靠证明;在相应的“User ID”和“Password”字段中填写值。

你遇到“Unexpected error…”了?

“Unexpected error in -[UIATarget_0x5a20d20 frontMostApp], /SourceCache/UIAutomation_Sim/UIAutomation-37/Framework/UIATargetElements.m line 437″

如果你遇到了这个错误,复制一个 com.apple.Accessibility.plist 到4.0.1就可以解决这个问题。

复制com.apple.Accessibility.plist~/Library/Application Support/iPhone Simulator/4.0.1/Library/Preferences

确保这个文件中仅有两个分别名为“AccessibilityEnabled”和“ApplicationAccessibilityEnabled”的键值,并且都经过效验。

授权

这篇文章及相关的源代码和文件,经过The Code Project Open License(CPOL)协议的授权。

关于作者

Adi Saxena

原文链接:http://www.codeproject.com/KB/iPhone/UI_Automation_Testing.aspx

原作者:Adi Saxena

原文:

How do I perform UI Automation testing in iOS 4

Beginner level guide (step by step) on UI Automation Testing in iOS 4

Download LoginWindow_Src – 39.4 KB

Introduction

It 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 iniOS4, its supported by 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 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 help of one sample application developed using Coco Touch framework.

Description

My sample application is having 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 mandatory requirement).

Now compile your application in debug mode.

Test Scripts:

As I mentioned above, test scripts are basically set of ordered commends. In other words, it’s conversion of textual test cases in to Java script which would be auto executed by “Automation” instrument.

Here is the sample test script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Get the handle of applications main window
var window = UIATarget.localTarget().frontMostApp().mainWindow(); 
 
// Get the handle of view
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(); 
 
// Check number of Text field(s)
if(textfields.length!=1)
{
   UIALogger.logFail("FAIL: Inavlid number of Text field(s)");
}
else
{
   UIALogger.logPass("PASS: Correct number of Text field(s)");
}
// Check number of Secure 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)");
} 
 
// Check number of static 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)");
} 
 
// Check number of buttons(s)
if(buttons.length!=1)
{
   UIALogger.logFail("FAIL: Inavlid number of button(s)");
}
else
{
   UIALogger.logPass("PASS: Correct number of button(s)");
} 
 
//TESTCASE_001 : Test Log on Screen
//Check existence of desired TextField On UIScreen
if(textfields["username"]==null || textfields["username"].toString() == "[object UIAElementNil]")
{
   UIALogger.logFail("FAIL:Desired textfield not found.");
}
else
{
   UIALogger.logPass("PASS: Desired UITextField is available");
} 
 
//TESTCASE_1.2 :Check existence desired of PasswordField On UIScreen
if(passwordfields[0]==null || passwordfields[0].toString() == "[object UIAElementNil]")
{
   UIALogger.logFail("FAIL:Desired UISecureField not found.");
}
else
{
   UIALogger.logPass("PASS: Desired UISecureField is available");
} 
 
//TESTCASE_1.3 :Check For Existence of Buttons On UIScreen
if(buttons["logon"]==null || buttons["logon"].toString() == "[object UIAElementNil]")
{
   UIALogger.logFail("FAIL:Desired UIButton not found.");
}
else
{
   UIALogger.logPass("PASS: Desired UIButton is available");
} 
 
//TESTCASE_001 : Missing User Name
/////////////////////////////////////// 
 
textfields["username"].setValue("");
passwordfields[0].setValue("password");
buttons["logon"].tap(); 
 
//target.delay(2); 
 
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");
} 
 
//TESTCASE_002 : Missing Password
//////////////////////////////////////////////// 
 
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");
} 
 
//TESTCASE_003 : Successful Log On
textfields["username"].setValue("username");
passwordfields[0].setValue("password");
buttons["logon"].tap();
target.delay(2);

All UI elements in application are represented to the script through an ordered hierarchy of objects defined by theUIAElements class and its subclasses like UIATarget,UIALogger etc.

For more information refer 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 time).

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 attached Sample code

Mac Mini (Intel processor based) with Snow Leopard 10.6 (or above) and iOS SDK 4.0

(1) Unzip attached “LoginWindow_src.zip”, compile it in debug mode and test it on Simulator.

(2) “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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Adi Saxena