Android自动化测试(UiAutomator)简要介绍

来源:互联网 发布:人民币转换软件 编辑:程序博客网 时间:2024/05/22 09:41

转:http://blog.csdn.net/zhubaitian/article/details/39520069

一、一个BUG引发的问题


    如果研发过程中有一个BUG:“不断的切换手机语言出现花屏现象”。这个问题我们如何验证呢?我想,最好的方式应该是自动化测试。
    那么,自动化测试可以完成哪些任务呢?
    简单的说,那些重复性的测试工作,都可以交给自动化完成:
        1、设置手机的语言
        2、添加、删除、收藏联系人
        3、拨号、挂断
        4、甚至发送短信、收藏短信

    如果需要上面的功能,那么就开始自动化之旅吧。


二、Android自动化测试简单介绍


    Android自动化测试主要分为Monkeyrunner、Rubotium、UiAutomator、Monkey(在我看来这个不算)等。主要特点:
    1、Monkeyrunner:优点:操作最为简单,可以录制测试脚本,可视化操作;缺点:主要生成坐标的自动化操作,移植性不强,功能最为局限;
    2、Rubotium:主要针对某一个APK进行自动化测试,APK可以有源码,也可以没有源码,功能强大;缺点是针对APK操作,而且需要对APK重新签名(有工具),因此操作相对复杂;
    3、UiAutomator:优点:可以对所有操作进行自动化,操作简单;缺点:Android版本需要高于4.0,无法根据控件ID操作,相对来说功能较为局限,但也够用了;
    4、Monkey:准确来说,这不算是自动化测试,因为其只能产生随机的事件,无法按照既定的步骤操作;
    由上面介绍可以有这样的结论:测试某个APK,可以选择Rubotium;测试过程可能涉及多个APK,选择UiAutomator;一些简单的测试,选择Monkeyrunner;

    本文主要介绍UiAutomator的使用方法。


三、环境搭建


3.1、必备条件:

    1、JDK
    2、SDK(API高于15)
    3、Eclipse(安装ADT插件)
    4、ANT(用于编译生成jar)

3.2、简要步骤:

    1、安装JDK并添加环境变量。
        安装后,一定要通过JAVA_HOME的方式添加环境变量,即先建立JAVA_HOME变量,然后在path中添加%JAVA_HOME%\bin;
    2、添加SDK环境变量。
        一定要先建立ANDROID_HOME,然后把%ANDROID_HOME%\tools添加到path中;
    3、安装Eclipse,并安装ADT插件。
    4、安装ANT工具,并添加环境变量。

        同样一定要先建立%ANT_HOME%变量,然后在path中添加%ANT_HOME%\bin


四、详细操作


4.1、建立工程

    用Eclipse新建Java Project,注意,不是Android Project!

4.2、添加JUnit库

    


4.3、添加Android库

    找到路径Android-sdk\platforms\android-17\下面的android.jar和uiautomator.jar添加进来:
    
    所有库添加完应该是这个样子:

    


4.4、在src中添加包,然后添加class文件

    文件内容为:

[java] view plaincopy
  1. package com;  
  2. import com.android.uiautomator.core.UiObject;  
  3. import com.android.uiautomator.core.UiObjectNotFoundException;  
  4. import com.android.uiautomator.core.UiScrollable;  
  5. import com.android.uiautomator.core.UiSelector;  
  6. import com.android.uiautomator.testrunner.UiAutomatorTestCase;  
  7.   
  8. public class Runner extends UiAutomatorTestCase {  
  9.   
  10.     public void testDemo() throws UiObjectNotFoundException {  
  11.         getUiDevice().pressHome();  
  12.         // 进入设置菜单  
  13.         UiObject settingApp = new UiObject(new UiSelector().text("Settings"));  
  14.         settingApp.click();  
  15.         //休眠3秒  
  16.         try {  
  17.             Thread.sleep(3000);  
  18.         } catch (InterruptedException e1) {  
  19.             // TODO Auto-generated catch block  
  20.             e1.printStackTrace();  
  21.         }  
  22.         // 进入语言和输入法设置  
  23.         UiScrollable settingItems = new UiScrollable( new UiSelector().scrollable(true));  
  24.   
  25.         UiObject languageAndInputItem = settingItems.getChildByText(  
  26.                 new UiSelector().text("Language & input"), "Language & input"true);  
  27.         languageAndInputItem.clickAndWaitForNewWindow();  
  28.           
  29.     }  
  30. }  
    上面工程路径在e:\workspace\AutoRunner,类全名为com.Runner,至于具体的作用我们现在不去关心。

4.5、找到SDK ID

    CMD进入\Android-sdk\tools\目录下,运行命令:
    android list
    查看API大于15的SDK的ID值,当前是6;
    

4.6、创建build文件

    仍然在\Android-sdk\tools\目录下,运行命令:
    android create uitest-project -n <name> -t <android-sdk-ID> -p <path>
    比如:
    android create uitest-project -n AutoRunner -t 6 -p e:\workspace\AutoRunner

    上面的name就是将来生成的jar包的名字,可以自己定义,android-sdk-ID就是上面看到的6;path是Eclipse新建的工程的路径;运行命令后,将会在工程的根目录下生成build.xml文件。如果没生成,检查上面的步骤。

文件内容如下:

<?xml version="1.0" encoding="UTF-8"?><project name="AutoRunner" default="help">    <!-- The local.properties file is created and updated by the 'android' tool.         It contains the path to the SDK. It should *NOT* be checked into         Version Control Systems. -->    <property file="local.properties" />    <!-- The ant.properties file can be created by you. It is only edited by the         'android' tool to add properties to it.         This is the place to change some Ant specific build properties.         Here are some properties you may want to change/update:         source.dir             The name of the source directory. Default is 'src'.         out.dir             The name of the output directory. Default is 'bin'.         For other overridable properties, look at the beginning of the rules         files in the SDK, at tools/ant/build.xml         Properties related to the SDK location or the project target should         be updated using the 'android' tool with the 'update' action.         This file is an integral part of the build system for your         application and should be checked into Version Control Systems.         -->    <property file="ant.properties" />    <!-- if sdk.dir was not set from one of the property file, then         get it from the ANDROID_HOME env var.         This must be done before we load project.properties since         the proguard config can use sdk.dir -->    <property environment="env" />    <condition property="sdk.dir" value="${env.ANDROID_HOME}">        <isset property="env.ANDROID_HOME" />    </condition>    <!-- The project.properties file is created and updated by the 'android'         tool, as well as ADT.         This contains project specific properties such as project target, and library         dependencies. Lower level build properties are stored in ant.properties         (or in .classpath for Eclipse projects).         This file is an integral part of the build system for your         application and should be checked into Version Control Systems. -->    <loadproperties srcFile="project.properties" />    <!-- quick check on sdk.dir -->    <fail            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."            unless="sdk.dir"    />    <!--        Import per project custom build rules if present at the root of the project.        This is the place to put custom intermediary targets such as:            -pre-build            -pre-compile            -post-compile (This is typically used for code obfuscation.                           Compiled code location: ${out.classes.absolute.dir}                           If this is not done in place, override ${out.dex.input.absolute.dir})            -post-package            -post-build            -pre-clean    -->    <import file="custom_rules.xml" optional="true" />    <!-- Import the actual build file.         To customize existing targets, there are two options:         - Customize only one target:             - copy/paste the target into this file, *before* the               <import> task.             - customize it to your needs.         - Customize the whole content of build.xml             - copy/paste the content of the rules files (minus the top node)               into this file, replacing the <import> task.             - customize to your needs.         ***********************         ****** IMPORTANT ******         ***********************         In all cases you must update the value of version-tag below to read 'custom' instead of an integer,         in order to avoid having your file be overridden by tools such as "android update project"    -->    <!-- version-tag: VERSION_TAG -->    <import file="${sdk.dir}/tools/ant/uibuild.xml" /></project>


4.7、编译生成jar

    CMD进入项目的工程目录,然后运行ant build,将使用ant编译生成jar,成功将会提示:
    

    然后会在bin目录下生成jar文件。

自己测试的例子如下:

E:\workspace\ecllipse\AutoRunner>ant buildBuildfile: E:\workspace\ecllipse\AutoRunner\build.xml-check-env: [checkenv] Android SDK Tools Revision 25.1.6 [checkenv] Installed at E:\Android\sdk-build-setup:[getbuildtools] Using latest Build Tools: 24.0.0 rc4     [echo] Resolving Build Target for AutoRunner...[getuitarget] Project Target:   Android 4.2.2[getuitarget] API level:        17     [echo] ----------     [echo] Creating output directories if needed...-pre-compile:compile:-post-compile:-dex:      [dex] input: E:\workspace\ecllipse\AutoRunner\bin\classes      [dex] Found Deleted Target File      [dex] Converting compiled files and external libraries into E:\workspace\ecllipse\AutoRunner\bin\classes.dex...-post-dex:-jar:      [jar] Building jar: E:\workspace\ecllipse\AutoRunner\bin\AutoRunner.jar-post-jar:build:BUILD SUCCESSFULTotal time: 0 secondsE:\workspace\ecllipse\AutoRunner>


4.8、push并运行jar

    adb push <jar文件路径> data/local/tmp
    adb shell uiautomator runtest <jar文件名> -c <工程中的类名,包含包名>
    比如:
    adb push e:\workspace\AutoRunner\bin\AutoRunner.jar data/local/tmp
    adb shell uiautomator runtest AutoRunner.jar -c com.Runner

    然后就能看到手机会按照Runner中的步骤自动执行。具体效果就是,进入设置菜单,然后再进入“语言和输入法”菜单


五、代码分析


    我们从几个最重要的对象来介绍。

5.1、UiDevice对象

    getUiDevice()的方法可以得到一个UiDevice的对象,通过这个对象可以完成一些针对设备的动作:
    click(int x, int y)
    ----在(x,y)表示的像素地方点击
    pressBack()
    pressDelete()
    pressEnter()
    pressHome()
    pressMenu()
    pressSearch()
    ----点击相应的按键
    wakeUp()
    ----当手机处于灭屏状态时,唤醒屏幕,并解锁。
    swipe(startX, startY, endX, endY, steps)
    ----在手机上滑动,从(startX,startY)到(endX,endY)。steps表示滑动的这个距离分为几步完成,数目越少,滑动幅度越大。
    setOrientationLeft()
    setOrientationRight()
    ----将手机向相应方向旋转。
    setOrientationNatural()
    ----将手机旋转状态回归正常。

5.2、UiSelector对象

    这个对象可以理解为一种条件对象,描述的是一种条件,经常配合UiObject使用,可以得到某个(某些)符合条件的控件对象。
    checked(boolean val)
    ----描述一种check状态为val的关系。
    className(className)
    ----描述一种类名为className的对象关系
    clickable(boolean val)
    ----与checked类似,描述clickable状态为val的关系
    description(desc)
    ----不解释
    descriptionContains(desc)
    ----与description类似
    focusable(boolean val)
    ----与checked类似
    index(index)
    ----用当前对象在父对象集中的索引作为描述
    packageName(String name)
    ----用包名作为条件描述
    selected(val)
    ----描述一种选择关系
    text(text)
    ----最为常用的一种关系,用控件上的文本即可找到当前控件,需要注意,所有使用text属性找到的控件,默认是英文的。支持中文,请看http://blog.csdn.net/zhangmiaoping23/article/details/51481146。
    textContains(text)
    ----与text类似
    textStartsWith(text)
    ----与text类似

5.3、UiObject对象

    这个对象可以理解为控件的对象。 一般一个UiObject对象可以通过一下形式得到:
    UiObject mItem = new UiObject(new UiSelector().text("English"));
    也就是配合一个UiSelector就可以得到一个控件。
    click()
    ----点击控件
    clickAndWaitForNewWindow()
    ----点击某个控件,并等待窗口刷新
    longClick()
    ----长按
    clearTextField()
    ----清除文本,主要针对编辑框
    getChildCount()
    ----这个方法可以看出,其实UiObject也可以是一个控件的集合
    getPackageName()
    ----得到控件的包名
    getSelector()
    ----得到当前控件的选择条件
    getText()
    ----得到控件上的Text
    isCheckable()
    isChecked()
    isClickable()
    isLongClickable()
    isScrollable()
    isScrollable()
    isSelected()
    ----判断是否具备某个属性

5.4、UiCollection对象

    这个对象可以理解为一个对象的集合。因为UiSelector描述后得到的有可能是多个满足条件的控件集合,因此可以用来生成UiCollection:
    UiCollection mUiCollection = new UiCollection(new UiSelector().text("Settings"));
    getChild(selector)
    ----从集合中再次通过UiSelector选择一个UiObject对象
    getChildByDescription(childPattern, text)
    ----从一个匹配模式中再次以text为条件选择UiObject
    getChildByText(childPattern, text)
    ----与上面类似。
    getChildCount()
    ----得到当前集合中控件的个数

5.5、UiScrollable对象

    UiScrollable可以生成一个滚动动作的对象,其最大的作用就是可以实现滚动的查找某个元素。比如在“设置”菜单中,“语言和输入法”这个菜单比较靠下,需要滚动后才可以看到(找到),因此就用上了UiScrollable:

[java] view plaincopy
  1. UiScrollable settingItems = new UiScrollable( new UiSelector().scrollable(true));  
  2. UiObject languageAndInputItem = settingItems.getChildByText(  
  3. new UiSelector().text("Language & input"), "Language & input",  
  4. true);  
    上面的形式就可以在滚动中查找显示有“Language & input”的控件,也就是“语言和输入法”的设置项。

5.6、等待操作和添加Log的方法

    如果是对于一个标准的UiObject对象,可以通过clickAndWaitForNewWindow的方法在点击之后主动等待一段事件,但是如果需要额外的等待一段时间,特别对于getUiDevice().pressHome();这种操作,可能需要很长的事件去为下一步操作获取更多的事件,此时我们可以使用线程的sleep方法去实现:

[java] view plaincopy
  1. //等待3秒  
  2. try {  
  3.     Thread.sleep(3000);  
  4. catch (InterruptedException e1) {  
  5.     e1.printStackTrace();  
  6. }  

    而添加Log的方法也可以通过Java标准的println来实现:
    System.out.println("This used to print some log!!!" + setLanItem.getText());
    以上Log将会在jar被运行时通过CMD窗口打印出来。


六、一个相对完整的测试case


    下面就用一个相对连贯的测试用例来串一下上面的知识点,这个case用例要做的就是进入系统设置菜单,然后选择“语言和输入法”菜单,然后进入“语言设置”菜单,然后在第一项上点击,把当前语言设置为“简体中文”:

[java] view plaincopy
  1. public void setChineseLan() throws UiObjectNotFoundException {  
  2.     //进入操作前,先用Home键进入待机界面  
  3.     getUiDevice().pressHome();  
  4.   
  5.   
  6.     //进入“系统设置”菜单。也可以通过点击menu按键来实现  
  7.     UiObject settingApp = new UiObject(new UiSelector().text("Settings"));  
  8.     settingApp.click();  
  9.   
  10.   
  11.     //等待3秒  
  12.     try {  
  13.         Thread.sleep(3000);  
  14.     } catch (InterruptedException e1) {  
  15.         e1.printStackTrace();  
  16.     }  
  17.   
  18.   
  19.     //用滚动的方式查找并进入“语言和输入法设置”菜单  
  20.     UiScrollable settingItems = new UiScrollable(  
  21.             new UiSelector().scrollable(true));  
  22.   
  23.   
  24.     UiObject languageAndInputItem = settingItems.getChildByText(  
  25.             new UiSelector().text("Language & input"), "Language & input",  
  26.             true);  
  27.     languageAndInputItem.clickAndWaitForNewWindow();  
  28.   
  29.   
  30.     //找到“English”的可点击项(因为当前是英文环境)  
  31.     UiObject setLanItem = new UiObject(new UiSelector().text("English"));  
  32.     setLanItem.clickAndWaitForNewWindow();  
  33.   
  34.   
  35.     //Log输出  
  36.     System.out.println("setLanItem-->" + setLanItem.getPackageName());  
  37.   
  38.   
  39.     //由于无法识别中文,因此我们这里使用坐标去选择“简体中文”项  
  40.     getUiDevice().click(350250);  
  41.       
  42.     //点击返回键,回到待机界面  
  43.     getUiDevice().pressBack();  
  44.     getUiDevice().pressBack();  

0 0
原创粉丝点击