1. 程式人生 > >Android自動化測試工具 UiAutomator使用詳解

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.實踐

分析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一下吧!

歡迎同學們吐槽評論,如果你覺得本篇部落格對你有用,那麼就留個言或者頂一下吧(^-^)