Android自动化测试工具 UiAutomator使用详解

封面

本文测试用例下载地址

1.介绍

Android团队在4.1版本(API 16)中推出了一款全新的UI自动化测试工具UiAutomator,用来帮助开发人员更有效率的完成App的Debug工作,同时对于测试人员也是一大福音,为什么这么说呢?

举个栗子

测试:“我发现了一个bug,你写的App打开A页面,再打开B页面有时会出现闪屏问题。”

开发:“嗯?还有这样的问题,复现给我看看。(内心独白:我写的App怎么会有bug,一定是你用的姿势不对)”

测试:一段忙碌的操作之后...“咦,怎么不出现了?”

开发:“那你先回去吧,复现再告诉我。”

几天过去了...

测试:满心欢喜状,“上次那个问题我复现了,操作给你看....我去,怎么又不出现了!”

开发:“是不是设备有问题,你换个设备再试试呢?”

测试:“宝宝心里苦,但是宝宝不说!”

有了UiAutomator之后:

测试:“我发现了一个bug,你写的App打开A页面,再打开B页面有时会出现闪屏问题。”

开发:“这个简单,我用UiAutomator写个测试用例,分分钟解决。”

测试:“厉害了Word哥!”

全剧终!

UiAutomator提供了以下两种工具来支持UI自动化测试:

  • uiautomatorviewer:用来分析UI控件的图形界面工具,位于SDK目录下的tools文件夹中。

  • uiautomator:一个java库,提供执行自动化测试的各种API。

2.环境搭建

本文使用了Android Studio作为IDE,Eclipse,Please go home!

Eclipse go home

首先在app根目录的build.gradle文件中加入依赖:

// AS默认配置,如果如果没有记得加上
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
    exclude group: 'com.android.support', module: 'support-annotations'
})
androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'

注意:uiautomator库支持的最低版本为API 18,所以本篇文章开发环境的minSdkVersion为18。

配置testInstrumentationRunner为AndroidJunitRunner:

defaultConfig {
    ...
    // 这个AS会为我们默认配置,如果没有记得加上
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}

看下完整的build.gradle文件:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.3"
    defaultConfig {
        applicationId "com.yl.uiautomatordemo"
        minSdkVersion 18
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.3.1'
    testCompile 'junit:junit:4.12'
    androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
}

在dependencies中用到了compile、testCompile、androidTestCompile三种依赖方式,让我们来看看他们有什么区别:

  • compile:参与编译,并且会打包到debug/release apk中。

  • testCompile:只参与单元测试编译,不会打包到debug/release apk包中,不需要设备支持。

  • androidTestCompile:只参与UI测试编译,不会打包到debug/release apk包中,需要设备支持。

除此之外还有Provided、APK、Debug compile和Release compile:

  • Provided:只参与编译,不会打包到debug/release apk中。

  • APK:不参与编译,只会打包到debug/release apk中。

  • Debug compile:只参与debug编译,只会打包到debug apk中。

  • Release compile:只参与release编译,只会打包到release apk中。

3.测试流程

  • 1.安装被测试App到手机中。

  • 2.打开UI分析工具uiautomatorviewer.bat,分析当前UI的界面元素,确保App的各个控件可以被测试工具获取到。

  • 3.根据App使用流程编写测试用例。

  • 4.运行测试用例进行测试,定位bug,解决bug。

4.实践

《可折叠的Toolbar—CollapsingToolbarLayout》中的Demo为例,假设反复滑动布局会导致应用crash,针对这种情况,我们来写一个测试用例:

分析UI的界面元素

启动被测试App,打开uiautomatorviewer.bat工具,点击左上角的Device Screenshot按钮捕获屏幕快照,如下图所示,左侧显示屏幕快照,右侧显示布局结构与控件属性,控件属性在编写测试用例时会用到。

分析UI的界面元素

编写测试用例

选择File—New—New Project新建项目,和创建普通项目的流程相同,只不过不需要创建Activity,创建完成后,项目结构如下图所示:

项目结构

可以看到,在app—src目录下,AS为我们自动创建了一个androidTest文件夹,用来编写UI测试用例,同级还有一个test文件夹,用来编写单元测试用例。

项目创建成功后,参考上文引入依赖,构建完成后,开始写测试用例吧!等等,先别急,在此之前先普及一下uiautomator的常用API:

  • UiDevice:

    设备对象,通过UiDevice的getInstance(instrumentation)方法获取,可以通过UiDevice实例来检测设备的各种属性,比如获取屏幕的方向、尺寸等,还可以通过UiDevice实例来执行设备级别的操作,比如点击Home键、返回键等:

    // 点击Home键
    uiDevice.pressHome();
    
    // 点击返回键
    uiDevice.pressBack();
    
    ...
    
  • UiSelector

    用于获取某些符合条件的UI控件对象,可以通过资源id、描述等熟悉获取:

    // 通过资源id获取
    new UiSelector().resourceId("com.yang.designsupportdemo:id/CollapsingToolbarLayout");
    
    // 通过描述文件获取
    new UiSelector().description("Navigate up")
    
    // 通过className获取
    new UiSelector().className("android.support.v7.widget.RecyclerView")
    
    ...
    
  • UiObject

    代表一个UI控件,通过uiDevice的findObject(UiSelector)方法获取,获取到UiObject实例后,就可以对UI控件进行相关的操作,比如点击、长按等:

    // 点击应用返回按钮
    UiObject back = uiDevice.findObject(new UiSelector().description("Navigate up"));
    back.click();
    
  • UiCollection

    代表UI控件集合,相当于ViewGroup,比如界面中有多个CheckBox时,可以通过类名获取到当前界面下的所有CheckBox,然后通过控件id获取指定的CheckBox对象:

    // 获取指定的CheckBox对象
    UiCollection uiCollection = new UiCollection(new UiSelector().className("类名"));
    UiObject checkBox = uiCollection.getChild(new UiSelector().resourceId(""));
    
  • UiScrollable

    代表可滚动的控件,比如打开设置的关于手机选项:

    // 滑动列表到最后,点击About phone选项
    UiScrollable settings = new UiScrollable(new UiSelector().className("android.support.v7.widget.RecyclerView"));
    UiObject about = settings.getChildByText(new UiSelector().className("android.widget.LinearLayout"), "About phone");
    about.click();
    

看下滚动效果:

打开关于手机

OK,常用API到这里就说的差不多了,开始写测试用例吧!

Talk is cheap, Show me the code.

public class UiTest extends TestCase {

    public void testA() throws UiObjectNotFoundException {
        // 获取设备对象
        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
        UiDevice uiDevice = UiDevice.getInstance(instrumentation);
        // 获取上下文
        Context context = instrumentation.getContext();

        // 启动测试App
        Intent intent = context.getPackageManager().getLaunchIntentForPackage("com.yang.designsupportdemo");
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
        context.startActivity(intent);

        // 打开CollapsingToolbarLayout
        String resourceId = "com.yang.designsupportdemo:id/CollapsingToolbarLayout";
        UiObject collapsingToolbarLayout = uiDevice.findObject(new UiSelector().resourceId(resourceId));
        collapsingToolbarLayout.click();

        for (int i = 0; i < 5; i++) {
            // 向上移动
            uiDevice.swipe(uiDevice.getDisplayHeight() / 2, uiDevice.getDisplayHeight(),
                    uiDevice.getDisplayHeight() / 2, uiDevice.getDisplayHeight() / 2, 10);

            // 向下移动
            uiDevice.swipe(uiDevice.getDisplayHeight() / 2, uiDevice.getDisplayHeight() / 2,
                    uiDevice.getDisplayHeight() / 2, uiDevice.getDisplayHeight(), 10);
        }

        // 点击应用返回按钮
        UiObject back = uiDevice.findObject(new UiSelector().description("Navigate up"));
        back.click();

        // 点击设备返回按钮
        uiDevice.pressBack();
    }
}

代码中写了很全的注释,简单说下,首先获取设备对象和上下文,这个后面要用到,然后启动测试App,打开需要测试的界面,上下滑动5次后退出App,由于上文中对API已经有了一定了解,看起代码来还是很轻松的。

注意:测试方法需要以test开头,如果存在多个测试方法,以test后的字母顺序执行。

代码写完了,接下来就要开始测试了,右击测试类选择Run按钮,或者点击测试类中的执行按钮进行测试,上面的按钮代表执行所有测试方法,下面的按钮代表只执行当前测试方法:

执行测试

测试执行后,可以看到控制台上打印了一些信息:

测试信息

可以看到,首先通过adb shell命令在设备中安装了UiAutomatorDemo和com.yl.uiautomatordemo.test两个apk,然后启动测试,此时被测App已经开始执行测试流程,执行完成后,显示测试结果,看下App的执行效果:

UI测试

OK,到这里,UiAutomator的基本用法就讲完了。

5.写在最后

源码已托管到GitHub上,欢迎Fork,觉得还不错就Start一下吧!

GitHub传送门

欢迎同学们吐槽评论,如果你觉得本篇博客对你有用,那么就留个言或者点下喜欢吧(^-^)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容