代码自动测试 android,借助 UiAutomator 实现自动 Android* 测试

UiAutomator 具备一些优势和缺点 。

优势:

可用于使用不同分辨率的设备显示器上

事件能够链接至 Android UI 控制。 例如,点击带有文本 “Ok” 的按钮,而无需点击坐标位置(x=450,y=550)。

能够复制复杂的用户操作序列

总是执行相同的动作序列,从而能够帮助我们在不同的设备上收集性能标准。

能够不改变任何 Java* 代码而多次运行并在不同的设备上运行

能够使用设备上的硬件按钮

缺点:

无法配合 OpenGL* 和 HTML5 应用使用,因为这些应用没有 Android UI 组件。

编写 JavaScript* 非常耗时

脚本部署

为了对如何使用 UiAutomator 进行介绍,我将展示一个简单的程序。 该程序是标准的 Android 信息应用,能够向任何一个手机号码发送短信。

以下简要介绍了我们实施的操作:

查找并运行应用程序

创建和发送短信

如您所见,这非常简单。

测试准备

为了分析 UI 界面,我们将使用 uiautomatorviewer。

39184fe8b46fe14d225fc062e3687be8.jpg

uiautomatorviewer 展示了 Node Detail 中所有 UI 组件的截屏,因此您能够看到不同的属性。 从属性中,您可以找到目标元素。

定制开发环境

如果您使用的是 Eclipse*:

在 Eclipse 中创建一个新的 Java 项目。 我们将该项目称为: SendMessage

在 Project Explorer 中右击您的项目并点击Properties项

在 Properties 中选择 Java Build Path,并添加所需的库:

点击 Add Library> JUnit 并在 JUnit3 中选择添加 JUnit 支持

点击 Add External JARs ...

在 /platforms/directory 中选择最新版的 SDK。 同样在该目录下,选择下列文件: uiautomator.jar 和 android.jar

如果您使用的是其他开发环境,请确保将 android.jar 和 uiautomator.jar 文件添加至项目设置中。

创建脚本

使用 Java 类在以前创建的文件中创建一个项目, 称其为:SendMessage。 该类继承了 UiAutomatorTestCase 类,使用 Ctrl + Shift + o 键(适用于 Eclipse),添加所需的库。

创建三个函数来测试该应用:

搜索并运行该应用

发送短信

退出应用的主功能表

创建一个可帮助我们运行上述所有特性的函数 — 一种主要函数:

public void test() {

// Here will be called for all other functions

}

查找并运行应用的函数

该函数非常简单。 按主页按钮,显示主窗口后,打开功能表并查找该应用的图标。 点击该图标启动应用。

private void findAndRunApp() throws UiObjectNotFoundException {

// Go to main screen

getUiDevice().pressHome();

// Find menu button

UiObject allAppsButton = new UiObject(new UiSelector()

.description("Apps"));

// Click on menu button and wait new window

allAppsButton.clickAndWaitForNewWindow();

// Find App tab

UiObject appsTab = new UiObject(new UiSelector()

.text("Apps"));

// Click on app tab

appsTab.click();

// Find scroll object (menu scroll)

UiScrollable appViews = new UiScrollable(new UiSelector()

.scrollable(true));

// Set the swiping mode to horizontal (the default is vertical)

appViews.setAsHorizontalList();

// Find Messaging application

UiObject settingsApp = appViews.getChildByText(new UiSelector()

.className("android.widget.TextView"), "Messaging");

// Open Messaging application

settingsApp.clickAndWaitForNewWindow();

// Validate that the package name is the expected one

UiObject settingsValidation = new UiObject(new UiSelector()

.packageName("com.android.mms"));

assertTrue("Unable to detect Messaging",

settingsValidation.exists());

}

所有的类名、按钮上的文本等均来自 uiautomatorviewer。

发送短信

该函数可查找并按下编写新应用的按钮,输入接收文本信息的电话号码并按发送按钮。 电话号码和文本可通过函数参数发送:

private void sendMessage(String toNumber, String text) throws UiObjectNotFoundException {

// Find and click New message button

UiObject newMessageButton = new UiObject(new UiSelector()

.className("android.widget.TextView").description("New message"));

newMessageButton.clickAndWaitForNewWindow();

// Find to box and enter the number into it

UiObject toBox = new UiObject(new UiSelector()

.className("android.widget.MultiAutoCompleteTextView").instance(0));

toBox.setText(toNumber);

// Find text box and enter the message into it

UiObject textBox = new UiObject(new UiSelector()

.className("android.widget.EditText").instance(0));

textBox.setText(text);

// Find send button and send message

UiObject sendButton = new UiObject(new UiSelector()

.className("android.widget.ImageButton").description("Send"));

sendButton.click();

}

显示电话号码和文本信息的字段没有任何特殊功能,因为这些字段的任何文本和描述都不可用。 因此,通过按照元素在界面层级中的排列位置在该实例中来使用元素,便可找到它们。

为了添加将参数传递至脚本的功能,我们可以指定想要发送该信息的位置的数量以及文本信息。 该函数测试()可初始化默认设置,如果系统通过命令行向任何参数发送信息,则可使用以下默认设置进行替换:

// Default parameters

String toNumber = "123456";

String text = "Test message";

String toParam = getParams().getString("to");

String textParam = getParams().getString("text");

if (toParam != null) {

// Remove spaces

toNumber = toParam.trim();

}

if (textParam != null) {

text = textParam.trim();

}

因此,我们可以使用小密钥 -e、参数的第一个名称和第二个值通过脚本中的命令行来传递参数。 例如,我的应用可以发送数字来发送 " 777777 »:-e 至 777777

您可能会遇到一些问题。 例如,该应用不理解一些字符而失败。 包含某些字符的文本无法传达,因为无法理解而失败。 比如:空格键、&、、(、) 、"、' 以及一些 Unicode 字符。 当使用这些字符编写字符串(如空间线:blogspaceblog)时,我将更换这些字符。 因此,当脚本启动 UiAutomator 时,我们将使用能够处理我们的输入参数的脚本。 我们添加了函数测试(),通过该测试,我们可以检查是否有选项、解析参数,如果有,可将其更换为实际字符。 以下是一个示例代码,演示了我们之前插入的内容:

if (toParam != null) {

toParam = toParam.replace("blogspaceblog", " ");

toParam = toParam.replace("blogamperblog", "&");

toParam = toParam.replace("bloglessblog", "

toParam = toParam.replace("blogmoreblog", ">");

toParam = toParam.replace("blogopenbktblog", "(");

toParam = toParam.replace("blogclosebktblog", ")");

toParam = toParam.replace("blogonequoteblog", "'");

toParam = toParam.replace("blogtwicequoteblog", """);

toNumber = toParam.trim();

}

if (textParam != null) {

textParam = textParam.replace("blogspaceblog", " ");

textParam = textParam.replace("blogamperblog", "&");

textParam = textParam.replace("bloglessblog", "

textParam = textParam.replace("blogmoreblog", ">");

textParam = textParam.replace("blogopenbktblog", "(");

textParam = textParam.replace("blogclosebktblog", ")");

textParam = textParam.replace("blogonequoteblog", "'");

textParam = textParam.replace("blogtwicequoteblog", """);

text = textParam.trim();

}

退出应用的主功能表

该函数是我们所实施的函数中最简单的一个。 仅需按下回环中的一个按钮,直至其显示该按钮,即可创建一条新信息。

private void exitToMainWindow() {

// Find New message button

UiObject newMessageButton = new UiObject(new UiSelector()

.className("android.widget.TextView").description("New message"));

// Press back button while new message button doesn't exist

while(!newMessageButton.exists()) {

getUiDevice().pressBack();

}

}

以下是我们的源代码:源代码

package blog.send.message;

import com.android.uiautomator.core.UiObject;

import com.android.uiautomator.core.UiObjectNotFoundException;

import com.android.uiautomator.core.UiScrollable;

import com.android.uiautomator.core.UiSelector;

import com.android.uiautomator.testrunner.UiAutomatorTestCase;

public class SendMessage extends UiAutomatorTestCase {

public void test() throws UiObjectNotFoundException {

// Default parameters

String toNumber = "123456";

String text = "Test message";

String toParam = getParams().getString("to");

String textParam = getParams().getString("text");

if (toParam != null) {

toParam = toParam.replace("blogspaceblog", " ");

toParam = toParam.replace("blogamperblog", "&");

toParam = toParam.replace("bloglessblog", "

toParam = toParam.replace("blogmoreblog", ">");

toParam = toParam.replace("blogopenbktblog", "(");

toParam = toParam.replace("blogclosebktblog", ")");

toParam = toParam.replace("blogonequoteblog", "'");

toParam = toParam.replace("blogtwicequoteblog", """);

toNumber = toParam.trim();

}

if (textParam != null) {

textParam = textParam.replace("blogspaceblog", " ");

textParam = textParam.replace("blogamperblog", "&");

textParam = textParam.replace("bloglessblog", "

textParam = textParam.replace("blogmoreblog", ">");

textParam = textParam.replace("blogopenbktblog", "(");

textParam = textParam.replace("blogclosebktblog", ")");

textParam = textParam.replace("blogonequoteblog", "'");

textParam = textParam.replace("blogtwicequoteblog", """);

text = textParam.trim();

}

findAndRunApp();

sendMessage(toNumber, text);

exitToMainWindow();

}

// Here will be called for all other functions

private void findAndRunApp() throws UiObjectNotFoundException {

// Go to main screen

getUiDevice().pressHome();

// Find menu button

UiObject allAppsButton = new UiObject(new UiSelector()

.description("Apps"));

// Click on menu button and wait new window

allAppsButton.clickAndWaitForNewWindow();

// Find App tab

UiObject appsTab = new UiObject(new UiSelector()

.text("Apps"));

// Click on app tab

appsTab.click();

// Find scroll object (menu scroll)

UiScrollable appViews = new UiScrollable(new UiSelector()

.scrollable(true));

// Set the swiping mode to horizontal (the default is vertical)

appViews.setAsHorizontalList();

// Find Messaging application

UiObject settingsApp = appViews.getChildByText(new UiSelector()

.className("android.widget.TextView"), "Messaging");

// Open Messaging application

settingsApp.clickAndWaitForNewWindow();

// Validate that the package name is the expected one

UiObject settingsValidation = new UiObject(new UiSelector()

.packageName("com.android.mms"));

assertTrue("Unable to detect Messaging",

settingsValidation.exists());

}

private void sendMessage(String toNumber, String text) throws UiObjectNotFoundException {

// Find and click New message button

UiObject newMessageButton = new UiObject(new UiSelector()

.className("android.widget.TextView").description("New message"));

newMessageButton.clickAndWaitForNewWindow();

// Find to box and enter the number into it

UiObject toBox = new UiObject(new UiSelector()

.className("android.widget.MultiAutoCompleteTextView").instance(0));

toBox.setText(toNumber);

// Find text box and enter the message into it

UiObject textBox = new UiObject(new UiSelector()

.className("android.widget.EditText").instance(0));

textBox.setText(text);

// Find send button and send message

UiObject sendButton = new UiObject(new UiSelector()

.className("android.widget.ImageButton").description("Send"));

sendButton.click();

}

private void exitToMainWindow() {

// Find New message button

UiObject newMessageButton = new UiObject(new UiSelector()

.className("android.widget.TextView").description("New message"));

// Press back button while new message button doesn't exist

while(!newMessageButton.exists()) {

getUiDevice().pressBack();

sleep(500);

}

}

}

如要生成测试组件的配置文件,请从命令行运行以下命令:编译并运行测试 UiAutomator

/tools/android create uitest-project -n -t  -p

,其中 是为测试 UiAutomator 而创建的项目的名称(在我们的案例中: SendMessage); 是所选的设备和 Android API Level(您可以获得已安装设备列表、组(/工具/ android 列表目标); 是包含该项目的目录的路径。

您必须导出环境变量 ANDROID_HOME:

Windows*:

set ANDROID_HOME=

UNIX*:

export ANDROID_HOME=

进入包含项目文件的目录 build.xml(在第 1 步中生成),并运行命令:

ant build

使用 adb push 将 JAR 文件复制至该设备:

adb push /data/local/tmp/

在我们的案例中,该命令为:

adb push /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)— 软件实习生

相关文章与资源:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值