借助 UiAutomator 实现自动 Android* 测试
来源:互联网 发布:软件小公司利润率 编辑:程序博客网 时间:2024/04/29 16:12
我将为大家介绍一款出色的工具,它能够自动测试 Android* 应用的 UI。 这款工具称为 UiAutomator。 您可以从下链接获得最新的文档: http://developer.android.com/tools/help/uiautomator/index.html 和http://developer.android.com/tools/testing/testing_ui.html
UiAutomator 具备一些优势和缺点 。
优势:
- 可用于使用不同分辨率的设备显示器上
- 事件能够链接至 Android UI 控制。 例如,点击带有文本 “Ok” 的按钮,而无需点击坐标位置(x=450,y=550)。
- 能够复制复杂的用户操作序列
- 总是执行相同的动作序列,从而能够帮助我们在不同的设备上收集性能标准。
- 能够不改变任何 Java* 代码而多次运行并在不同的设备上运行
- 能够使用设备上的硬件按钮
缺点:
- 无法配合 OpenGL* 和 HTML5 应用使用,因为这些应用没有 Android UI 组件。
- 编写 JavaScript* 非常耗时
脚本部署
为了对如何使用 UiAutomator 进行介绍,我将展示一个简单的程序。 该程序是标准的 Android 信息应用,能够向任何一个手机号码发送短信。
以下简要介绍了我们实施的操作:
- 查找并运行应用程序
- 创建和发送短信
如您所见,这非常简单。
测试准备
为了分析 UI 界面,我们将使用 uiautomatorviewer。
uiautomatorviewer 展示了 Node Detail 中所有 UI 组件的截屏,因此您能够看到不同的属性。 从属性中,您可以找到目标元素。
定制开发环境
如果您使用的是 Eclipse*:
- 在 Eclipse 中创建一个新的 Java 项目。 我们将该项目称为: SendMessage
- 在 Project Explorer 中右击您的项目并点击Properties 项
- 在 Properties 中选择 Java Build Path,并添加所需的库:
- 点击 Add Library > JUnit 并在 JUnit3 中选择添加 JUnit 支持
- 点击 Add External JARs ...
- 在 <android-sdk>/platforms/directory 中选择最新版的 SDK。 同样在该目录下,选择下列文件:uiautomator.jar 和 android.jar
如果您使用的是其他开发环境,请确保将 android.jar 和 uiautomator.jar 文件添加至项目设置中。
创建脚本
使用 Java 类在以前创建的文件中创建一个项目, 称其为:SendMessage。 该类继承了 UiAutomatorTestCase 类,使用 Ctrl + Shift + o 键(适用于 Eclipse),添加所需的库。
创建三个函数来测试该应用:
- 搜索并运行该应用
- 发送短信
- 退出应用的主功能表
创建一个可帮助我们运行上述所有特性的函数 — 一种主要函数:
1
public
void
test() {
2
// Here will be called for all other functions
3
}
查找并运行应用的函数
该函数非常简单。 按主页按钮,显示主窗口后,打开功能表并查找该应用的图标。 点击该图标启动应用。
01
private
void
findAndRunApp() throws UiObjectNotFoundException {
02
// Go to main screen
03
getUiDevice().pressHome();
04
// Find menu button
05
UiObject allAppsButton =
new
UiObject(
new
UiSelector()
06
.description(
"Apps"
));
07
// Click on menu button and wait new window
08
allAppsButton.clickAndWaitForNewWindow();
09
// Find App tab
10
UiObject appsTab =
new
UiObject(
new
UiSelector()
11
.text(
"Apps"
));
12
// Click on app tab
13
appsTab.click();
14
// Find scroll object (menu scroll)
15
UiScrollable appViews =
new
UiScrollable(
new
UiSelector()
16
.scrollable(
true
));
17
// Set the swiping mode to horizontal (the default is vertical)
18
appViews.setAsHorizontalList();
19
// Find Messaging application
20
UiObject settingsApp = appViews.getChildByText(
new
UiSelector()
21
.className(
"android.widget.TextView"
),
"Messaging"
);
22
// Open Messaging application
23
settingsApp.clickAndWaitForNewWindow();
24
25
// Validate that the package name is the expected one
26
UiObject settingsValidation =
new
UiObject(
new
UiSelector()
27
.packageName(
"com.android.mms"
));
28
assertTrue(
"Unable to detect Messaging"
,
29
settingsValidation.exists());
30
}
所有的类名、按钮上的文本等均来自 uiautomatorviewer。
发送短信
该函数可查找并按下编写新应用的按钮,输入接收文本信息的电话号码并按发送按钮。 电话号码和文本可通过函数参数发送:
01
private
void
sendMessage(String toNumber, String text) throws UiObjectNotFoundException {
02
// Find and click New message button
03
UiObject newMessageButton =
new
UiObject(
new
UiSelector()
04
.className(
"android.widget.TextView"
).description(
"New message"
));
05
newMessageButton.clickAndWaitForNewWindow();
06
07
// Find to box and enter the number into it
08
UiObject toBox =
new
UiObject(
new
UiSelector()
09
.className(
"android.widget.MultiAutoCompleteTextView"
).instance(0));
10
toBox.setText(toNumber);
11
// Find text box and enter the message into it
12
UiObject textBox =
new
UiObject(
new
UiSelector()
13
.className(
"android.widget.EditText"
).instance(0));
14
textBox.setText(text);
15
16
// Find send button and send message
17
UiObject sendButton =
new
UiObject(
new
UiSelector()
18
.className(
"android.widget.ImageButton"
).description(
"Send"
));
19
sendButton.click();
20
}
显示电话号码和文本信息的字段没有任何特殊功能,因为这些字段的任何文本和描述都不可用。 因此,通过按照元素在界面层级中的排列位置在该实例中来使用元素,便可找到它们。
为了添加将参数传递至脚本的功能,我们可以指定想要发送该信息的位置的数量以及文本信息。 该函数测试()可初始化默认设置,如果系统通过命令行向任何参数发送信息,则可使用以下默认设置进行替换:
01
// Default parameters
02
String toNumber =
"123456"
;
03
String text =
"Test message"
;
04
05
String toParam = getParams().getString(
"to"
);
06
String textParam = getParams().getString(
"text"
);
07
if
(toParam != null) {
08
// Remove spaces
09
toNumber = toParam.trim();
10
}
11
if
(textParam != null) {
12
text = textParam.trim();
13
}
因此,我们可以使用小密钥 -e、参数的第一个名称和第二个值通过脚本中的命令行来传递参数。 例如,我的应用可以发送数字来发送 " 777777 »:-e 至 777777
您可能会遇到一些问题。 例如,该应用不理解一些字符而失败。 包含某些字符的文本无法传达,因为无法理解而失败。 比如:空格键、&、<、>、(、) 、"、' 以及一些 Unicode 字符。 当使用这些字符编写字符串(如空间线:blogspaceblog)时,我将更换这些字符。 因此,当脚本启动 UiAutomator 时,我们将使用能够处理我们的输入参数的脚本。 我们添加了函数测试(),通过该测试,我们可以检查是否有选项、解析参数,如果有,可将其更换为实际字符。 以下是一个示例代码,演示了我们之前插入的内容:
01
if
(toParam != null) {
02
toParam = toParam.replace(
"blogspaceblog"
,
" "
);
03
toParam = toParam.replace(
"blogamperblog"
,
"&"
);
04
toParam = toParam.replace(
"bloglessblog"
,
"<"
);
05
toParam = toParam.replace(
"blogmoreblog"
,
">"
);
06
toParam = toParam.replace(
"blogopenbktblog"
,
"("
);
07
toParam = toParam.replace(
"blogclosebktblog"
,
")"
);
08
toParam = toParam.replace(
"blogonequoteblog"
,
"'"
);
09
toParam = toParam.replace(
"blogtwicequoteblog"
,
"\""
);
10
toNumber = toParam.trim();
11
}
12
if
(textParam != null) {
13
textParam = textParam.replace(
"blogspaceblog"
,
" "
);
14
textParam = textParam.replace(
"blogamperblog"
,
"&"
);
15
textParam = textParam.replace(
"bloglessblog"
,
"<"
);
16
textParam = textParam.replace(
"blogmoreblog"
,
">"
);
17
textParam = textParam.replace(
"blogopenbktblog"
,
"("
);
18
textParam = textParam.replace(
"blogclosebktblog"
,
")"
);
19
textParam = textParam.replace(
"blogonequoteblog"
,
"'"
);
20
textParam = textParam.replace(
"blogtwicequoteblog"
,
"\""
);
21
text = textParam.trim();
22
}
退出应用的主功能表
该函数是我们所实施的函数中最简单的一个。 仅需按下回环中的一个按钮,直至其显示该按钮,即可创建一条新信息。
01
private
void
exitToMainWindow() {
02
// Find New message button
03
UiObject newMessageButton =
new
UiObject(
new
UiSelector()
04
.className(
"android.widget.TextView"
).description(
"New message"
));
05
06
// Press back button while new message button doesn't exist
07
while
(!newMessageButton.exists()) {
08
getUiDevice().pressBack();
09
}
10
}
以下是我们的源代码:源代码
001
package blog.send.message;
002
import com.android.uiautomator.core.UiObject;
003
import com.android.uiautomator.core.UiObjectNotFoundException;
004
import com.android.uiautomator.core.UiScrollable;
005
import com.android.uiautomator.core.UiSelector;
006
import com.android.uiautomator.testrunner.UiAutomatorTestCase;
007
008
public
class
SendMessage extends UiAutomatorTestCase {
009
public
void
test() throws UiObjectNotFoundException {
010
// Default parameters
011
String toNumber =
"123456"
;
012
String text =
"Test message"
;
013
014
String toParam = getParams().getString(
"to"
);
015
String textParam = getParams().getString(
"text"
);
016
if
(toParam != null) {
017
toParam = toParam.replace(
"blogspaceblog"
,
" "
);
018
toParam = toParam.replace(
"blogamperblog"
,
"&"
);
019
toParam = toParam.replace(
"bloglessblog"
,
"<"
);
020
toParam = toParam.replace(
"blogmoreblog"
,
">"
);
021
toParam = toParam.replace(
"blogopenbktblog"
,
"("
);
022
toParam = toParam.replace(
"blogclosebktblog"
,
")"
);
023
toParam = toParam.replace(
"blogonequoteblog"
,
"'"
);
024
toParam = toParam.replace(
"blogtwicequoteblog"
,
"\""
);
025
toNumber = toParam.trim();
026
}
027
if
(textParam != null) {
028
textParam = textParam.replace(
"blogspaceblog"
,
" "
);
029
textParam = textParam.replace(
"blogamperblog"
,
"&"
);
030
textParam = textParam.replace(
"bloglessblog"
,
"<"
);
031
textParam = textParam.replace(
"blogmoreblog"
,
">"
);
032
textParam = textParam.replace(
"blogopenbktblog"
,
"("
);
033
textParam = textParam.replace(
"blogclosebktblog"
,
")"
);
034
textParam = textParam.replace(
"blogonequoteblog"
,
"'"
);
035
textParam = textParam.replace(
"blogtwicequoteblog"
,
"\""
);
036
text = textParam.trim();
037
}
038
findAndRunApp();
039
sendMessage(toNumber, text);
040
exitToMainWindow();
041
}
042
// Here will be called for all other functions
043
private
void
findAndRunApp() throws UiObjectNotFoundException {
044
// Go to main screen
045
getUiDevice().pressHome();
046
// Find menu button
047
UiObject allAppsButton =
new
UiObject(
new
UiSelector()
048
.description(
"Apps"
));
049
// Click on menu button and wait new window
050
allAppsButton.clickAndWaitForNewWindow();
051
// Find App tab
052
UiObject appsTab =
new
UiObject(
new
UiSelector()
053
.text(
"Apps"
));
054
// Click on app tab
055
appsTab.click();
056
// Find scroll object (menu scroll)
057
UiScrollable appViews =
new
UiScrollable(
new
UiSelector()
058
.scrollable(
true
));
059
// Set the swiping mode to horizontal (the default is vertical)
060
appViews.setAsHorizontalList();
061
// Find Messaging application
062
UiObject settingsApp = appViews.getChildByText(
new
UiSelector()
063
.className(
"android.widget.TextView"
),
"Messaging"
);
064
// Open Messaging application
065
settingsApp.clickAndWaitForNewWindow();
066
067
// Validate that the package name is the expected one
068
UiObject settingsValidation =
new
UiObject(
new
UiSelector()
069
.packageName(
"com.android.mms"
));
070
assertTrue(
"Unable to detect Messaging"
,
071
settingsValidation.exists());
072
}
073
074
private
void
sendMessage(String toNumber, String text) throws UiObjectNotFoundException {
075
// Find and click New message button
076
UiObject newMessageButton =
new
UiObject(
new
UiSelector()
077
.className(
"android.widget.TextView"
).description(
"New message"
));
078
newMessageButton.clickAndWaitForNewWindow();
079
080
// Find to box and enter the number into it
081
UiObject toBox =
new
UiObject(
new
UiSelector()
082
.className(
"android.widget.MultiAutoCompleteTextView"
).instance(0));
083
toBox.setText(toNumber);
084
// Find text box and enter the message into it
085
UiObject textBox =
new
UiObject(
new
UiSelector()
086
.className(
"android.widget.EditText"
).instance(0));
087
textBox.setText(text);
088
089
// Find send button and send message
090
UiObject sendButton =
new
UiObject(
new
UiSelector()
091
.className(
"android.widget.ImageButton"
).description(
"Send"
));
092
sendButton.click();
093
}
094
095
private
void
exitToMainWindow() {
096
// Find New message button
097
UiObject newMessageButton =
new
UiObject(
new
UiSelector()
098
.className(
"android.widget.TextView"
).description(
"New message"
));
099
100
// Press back button while new message button doesn't exist
101
while
(!newMessageButton.exists()) {
102
getUiDevice().pressBack();
103
sleep(500);
104
}
105
}
106
}
如要生成测试组件的配置文件,请从命令行运行以下命令:编译并运行测试 UiAutomator
- <android-sdk>/tools/android create uitest-project -n <name> -t <target-id> -p <path>
,其中 <name> 是为测试 UiAutomator 而创建的项目的名称(在我们的案例中: SendMessage);<target-id> 是所选的设备和 Android API Level(您可以获得已安装设备列表、组(<android-sdk>/工具/ android 列表目标);<path> 是包含该项目的目录的路径。 - 您必须导出环境变量 ANDROID_HOME:
- Windows*:
set ANDROID_HOME=<path_to_your_sdk> - UNIX*:
export ANDROID_HOME=<path_to_your_sdk>
- Windows*:
- 进入包含项目文件的目录 build.xml(在第 1 步中生成),并运行命令:
ant build - 使用 adb push 将 JAR 文件复制至该设备:
adb push <path_to_output_jar> /data/local/tmp/
在我们的案例中,该命令为:
adb push <project_dir>/bin/SendMessage.jar /data/local/tmp/ - 运行该脚本:
adb shell uiautomator runtest /data/local/tmp/SendMessage.jar –c blog.send.message.SendMessage
关于作者
Egor Churaev (egor.churaev@intel.com)— 软件实习生
相关文章与资源:
- HTML5 - 英特尔开发人员专区
- Android - 英特尔开发人员专区
- 借助 UiAutomator 实现自动 Android* 测试
- UiAutomator Android 的自动测试框架(UiAutomator 快速调试)
- 基于UIAutomator+Jenkins Android自动化测试 实现
- 基于UIAutomator+Jenkins Android自动化测试 实现
- Android 借助 Python 实现自动上传蒲公英
- UiAutomator python+uiautomator 自动义测试框架
- android自动测试方法分析(monkeyrunner,robotium,uiautomator)
- android自动测试方法分析(monkeyrunner,robotium,uiautomator)
- UiAutomator Android 的自动测试框架(基础)
- android uiautomator自动化测试
- UiAutomator android自动化测试
- android ui测试uiautomator
- Android-自动化测试UIAutomator
- Android自动化测试uiautomator
- android studio测试--Uiautomator
- Android UiAutoMator自动化测试
- Android Uiautomator 自动化测试
- Android Uiautomator 自动化测试
- URL传递中文乱码的解决方法
- pl/sql developer 使用技巧
- Eclipse下加载AndroidSDK源码
- Windows 2008 因系统版本不能安装oracle10g(http://blog.sina.com.cn/u/1965435215)
- ie兼容响应式布局的实现总结 和 针对ie浏览器的CSS
- 借助 UiAutomator 实现自动 Android* 测试
- live555代码解读
- 关于Spring的69个面试问答——终极列表
- Android实现程序前后台切换效果
- JVM调优总结(十)——调优方法
- Asp.Net MVC4.0 官方教程 入门指南之二--添加一个控制器
- Apple Swift 编程语言简单入门(上)
- MyEclipse参加jquery.js文件missing semicolon的错误
- 在.NET中如何取得代码行数