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傳送門

歡迎同學們吐槽評論,如果你覺得本篇博客對你有用,那么就留個言或者點下喜歡吧(^-^)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容