借助 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 信息应用,能够向任何一个手机号码发送短信。

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

  1. 查找并运行应用程序
  2. 创建和发送短信

如您所见,这非常简单。

测试准备

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

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

定制开发环境

如果您使用的是 Eclipse*:

  1. 在 Eclipse 中创建一个新的 Java 项目。 我们将该项目称为: SendMessage
  2. 在 Project Explorer 中右击您的项目并点击Properties 
  3. 在 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. 搜索并运行该应用
  2. 发送短信
  3. 退出应用的主功能表

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

1public void test() {
2    // Here will be called for all other functions
3    }

查找并运行应用的函数

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

01private 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。

发送短信

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

01private 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");
07if (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 时,我们将使用能够处理我们的输入参数的脚本。 我们添加了函数测试(),通过该测试,我们可以检查是否有选项、解析参数,如果有,可将其更换为实际字符。 以下是一个示例代码,演示了我们之前插入的内容:

01if (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        }

退出应用的主功能表

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

01private 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    }

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

001package blog.send.message;
002import com.android.uiautomator.core.UiObject;
003import com.android.uiautomator.core.UiObjectNotFoundException;
004import com.android.uiautomator.core.UiScrollable;
005import com.android.uiautomator.core.UiSelector;
006import com.android.uiautomator.testrunner.UiAutomatorTestCase;
007 
008public 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

  1. <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> 是包含该项目的目录的路径。
  2. 您必须导出环境变量 ANDROID_HOME:
    • Windows*:
      set ANDROID_HOME=<path_to_your_sdk>
    • UNIX*:
      export ANDROID_HOME=<path_to_your_sdk>
  3. 进入包含项目文件的目录 build.xml(在第 1 步中生成),并运行命令:
    ant build
  4. 使用 adb push 将 JAR 文件复制至该设备:
    adb push <path_to_output_jar> /data/local/tmp/
    在我们的案例中,该命令为:
    adb push <project_dir>/bin/SendMessage.jar /data/local/tmp/
  5. 运行该脚本:
    adb shell uiautomator runtest /data/local/tmp/SendMessage.jar –c blog.send.message.SendMessage

关于作者

Egor Churaev (egor.churaev@intel.com)— 软件实习生

相关文章与资源:

  • HTML5 - 英特尔开发人员专区
  • Android - 英特尔开发人员专区
2 0
原创粉丝点击