使用uiautomator做UI測試

在Android 4.1發佈的時候包含了一種新的測試工具– uiautomator ,uiautomator是用來做UI測試的。也就是普通的手工測試,點擊每個控件元素 看看輸出的結果是否符合預期。比如 登陸界面 分別輸入正確和錯誤的用戶名密碼然後點擊登陸按鈕看看是否能否登陸以及是否有錯誤提示等。

功能性或者黑盒UI測試不需要測試人員瞭解程序如何實現的,只需要驗證各種操作的結果是否符合預期即可。這樣的測試可以分離團隊的開發人員和測試人員。大家各幹各的沒有太多的交集。

常用的UI測試方式就是人工驗證啦,就是測試人員拿着各種手機分別安裝要測試的程序然後看看是否能正確完成各種預定的功能。但是這種驗證方式是非常耗時間的,每次迴歸都要全部驗證一邊,並且還容易出現人爲錯誤。比較高效和可靠的UI測試方式就是自動化測試。自動化UI測試創建測試代碼來執行測試任務,各種測試任務分別覆蓋不同的使用場景,然後使用測試框架來運行這些測試任務。

uiautomator 就是你的自動化UI測試工具。
概述

Android SDK在4.1中提供瞭如下工具來支持UI自動化測試:

uiautomatorviewer – 一個圖形界面工具來掃描和分析應用的UI控件。
uiautomator – 一個測試的Java庫,包含了創建UI測試的各種API和執行自動化測試的引擎。

要使用該工具,需要滿足如下條件:

Android SDK Tools, Revision 21 or higher
Android SDK Platform, API 16 or higher

uiautomator 測試工具的工作流程

下面是uiautomator 工作流程概述:

安裝要測試的應用到手機中,分析應用的UI界面元素 並確保被測試應用的各個控件可以被測試工具獲取到。
創建知道測試案例來模擬應用中的用戶操作步驟。
編譯測試案例代碼爲Jar包並複製該Jar包到安裝了待測應用的測試手機中。
運行測試並查看結果
修改任何發現的bug,然後修復並重新測試。

分析待測應用的UI元素

在開始編寫測試案例代碼之前,需要熟悉待測應用的UI元素。可以通過uiautomatorviewer 工具來獲取應用的界面截圖並分析。uiautomatorviewer 工具提供了一個便利的方式來查看UI佈局結構,並且可以查看各個控件的相關屬性。利用這些信息可以用來創建UI測試代碼。
uiautomatorviewer 工具截圖

uiautomatorviewer 工具截圖

分析待測應用UI界面的步驟如下:

  1. 把Android手機連接到電腦上
  2. 打開命令行窗口並導航到目錄 /tools/
    運行如下命令:$ uiautomatorviewer

windows下運行 uiautomatorviewer.bat 命令
3. 點擊uiautomatorviewer 工具右上角文件夾按鈕旁邊的“Device Screenshot”按鈕來獲取當前 屏幕界面信息。
注意:如果當前電腦連接了多個設備,通過設置ANDROID_SERIAL環境變量來指定要分析的設備。步驟如下:
a.運行如下命令獲取連接到電腦的設備序列號
$ adb devices
b.設置ANDROID_SERIAL爲需要測試的設備序列號
Windows:set ANDROID_SERIAL=
Unix: export ANDROID_SERIAL=
如果電腦只連接一個設備則無需設置ANDROID_SERIAL 環境變量。

  1. 查看待測應用的UI界面元素屬性
    把鼠標放到uiautomatorviewer工具左邊的截圖中的控件上來查看該控件的屬性。屬性顯示在右側界面下方,上方顯示當前界面的佈局結構。
    點擊右側上方的黃三角按鈕(Toggle NAF Nodes)來查看不能被uiautomator測試工具訪問到的控件。這些控件只設置了有限的屬性,所以導致uiautomator無法獲取到這些控件。所以你可能很難測試這些控件。這種情況下你可以要求開發者爲這些控件添加必要的屬性,比如 如果是ImageView或者ImageButton應該添加android:contentDescription屬性。
    測試準備工作

在開始使用uiautomator 之前需要完成如下準備工作:
把待測應用安裝到測試手機(設備)上

當你準備測試的時候,待測的應用可能還沒有發佈到市場上。但是你應該具有該應用的APK安裝文件,你可以通過ADB工具來安裝待測應用到手機中,或者通過其他工具來安裝Apk。
辨別待測應用UI控件

在開始編寫uiautomator測試代碼之前,需要先辨別待測應用的UI控件元素。一般而言,優秀的待測應用的UI元素應該是可見的並且用戶可以操作的。這些UI元素也應該具有可見的文本標籤、android:contentDescription值或者二則兼具。

通過uiautomatorviewer 工具可以查看應用的可見控件。具體使用情況見上面所述。
確保待測應用是可訪問的

由於uiautomator 工具依賴Android設備的可訪問行來獲取UI控件,所以這不是非常重要的。要支持uiautomator 工具需要一下條件:

使用android:contentDescription屬性給 ImageButton, ImageView, CheckBox和其他控件設置標籤。
使用android:hint 屬性來標記EditText 控件,而不是使用裏面的文本(文本內容用戶是可以修改的)。
對於用來提供操作視覺反饋的UI(文本或者圖標),都添加一個android:hint 屬性來識別。
確保所有用戶可操作的界面元素都可以通過方向控制鍵選中(例如軌跡球)。
通過uiautomatorviewer 工具來確保所有的UI元素都可以被測試工具訪問到。還可以通過“輔助功能”(在設置界面)中的“TalkBack”等服務來測試UI的可訪問性。

設置開發環境

如果你使用的是Eclipse(Adt),則Android SDK提供了額外的工具來幫助你編寫uiautomator測試代碼和打包測試項目。在Eclipse中創建uiautomator測試項目的過程如下:

創建新的Java項目(注意不是Android項目)。在該項目中來創建測試代碼。
在Project Explorer視圖中,右鍵點擊測試項目,選擇“ Properties > Java Build Path”,然後選擇“Libraries” tab界面。在“Libraries”界面選擇“ Add Library > JUnit”來添加JUnit3 庫。然後點擊“Add External JARs… ”並導航到Android SDK目錄。選擇platforms目錄下面的 uiautomator.jar 和 android.jar文件。
設置好的build path如下圖:

uiautomator項目類路徑設置

uiautomator項目類路徑設置

如果你不使用Eclipse,則需要確保/platforms/目錄中的uiautomator.jar 和 android.jar 位於項目Build path中。

配置好開發環境後就可以開始編寫測試代碼了。
創建uiautomator 測試案例

uiautomator 測試案例(Test case)需要繼承至UiAutomatorTestCase 類。而UiAutomatorTestCase 類繼承至junit.framework.TestCase類,所以可以用JUnit的Assert類來比較測試結果。

UI測試的首要任務就是訪問測試手機。一般都是從手機的主屏開始測試的。通過uiautomator 提供的API可以從主屏來模擬用戶的操作。下面會介紹具體示例。
uiautomator API

uiautomator API在 uiautomator.jar 文件中。這些API分別如下:
UiDevice

代表設備狀態。在測試中,可以通過UiDevice實例來檢測設備的各種屬性,例如當前的屏幕方向以及屏幕尺寸。同時還可以通過UiDevice實例來執行設備級別的操作,例如 把設備設置爲橫屏或者豎屏、按下Home按鍵等。

如下是模擬按下Home按鍵的代碼:
getUiDevice().pressHome();
UiSelector

代表一個搜索UI控件的條件。如果發現多個滿足條件的控件則會返回第一個控件。返回的結果爲UiObject對象。在構造UiSelector的時候可以組合使用多個屬性來定位具體的控件。如果沒有找到控件則會拋出 UiAutomatorObjectNotFoundException 異常。還可以使用childSelector()函數來嵌套UiSelector 對象。例如,下面的代碼演示瞭如何在當前界面中查找第一個ListView中的帶有文本屬性爲Apps的子控件。

UiObject appItem = new UiObject(new UiSelector()
.className(“android.widget.ListView”).instance(1)
.childSelector(new UiSelector().text(“Apps”)));

UiObject

代表一個UI控件。通過UiSelector來查找UiObject。
如下示例代碼演示瞭如何查找當前顯示界面中的取消按鈕和確認按鈕:

UiObject cancelButton = new UiObject(new UiSelector().text(“Cancel”));
UiObject okButton = new UiObject(new UiSelector().text(“OK”));

查找到的UiObject實例可以在其他測試代碼中重用。需要注意的是:每次使用UiObject做操作的時候uiautomator 都會在當前屏幕重新查找該控件。

如下代碼uiautomator 工具在當前界面查找文本內容爲“OK”的控件。如果存在並且可用則模擬用戶點擊該控件。

if(okButton.exists() && okButton.isEnabled())
{
okButton.click();
}

還可以限制僅僅查找特定類型的控件。例如 如下代碼只查找文本爲“Cancel”和“OK”的android.widget.Button類型控件。

UiObject cancelButton = new UiObject(new UiSelector().text(“Cancel”)
.className(“android.widget.Button”));
UiObject okButton = new UiObject(new UiSelector().text(“OK”)
.className(“android.widget.Button”));

UiCollection

代表控件的集合。獲取UiCollection的方式和UiObject一樣,通過 UiSelector查找。 UiCollection對應Android系統中的ViewGroup以及子控件。
如下代碼演示如何通過UiSelector來獲取包含視頻集合的UiCollection。

UiCollection videos = new UiCollection(new UiSelector()
.className(“android.widget.FrameLayout”));

如果每個視頻是放到LinearLayout中的,則可以通過如下方式獲取視頻的數目:

int count = videos.getChildCount(new UiSelector()
.className(“android.widget.LinearLayout”));

如果需要查找標籤爲“Cute Baby Laughing”的視頻,並點擊。則可以通過如下方式:

UiObject video = videos.getChildByText(new UiSelector()
.className(“android.widget.LinearLayout”), “Cute Baby Laughing”);
video.click();

同樣還可以模擬其他用戶操作。例如,模擬選擇視頻的操作如下:

UiObject checkBox = video.getChild(new UiSelector()
.className(“android.widget.Checkbox”));
if(!checkBox.isSelected()) checkbox.click();

UiScrollable

代表可滾動的控件。可以用UiScrollable來模擬水平或者垂直滾動的UI元素。如果需要操作的元素在屏幕外需要滾動屏幕才能看到的情況下需要使用UiScrollable。

例如,下面的代碼顯示瞭如何模擬滾動到“Settings ”菜單並點擊“About tablet”菜單的操作。

UiScrollable settingsItem = new UiScrollable(new UiSelector()
.className(“android.widget.ListView”));
UiObject about = settingsItem.getChildByText(new UiSelector()
.className(“android.widget.LinearLayout”), “About tablet”);
about.click()

其他API參考uiautomator api文檔。
一個簡單的uiautomator 測試案例

如下是一個簡單的測試案例代碼,模擬了點擊Home鍵回到主屏,然後點擊所以應用按鈕打開所有應用列表,並滾動到時鐘應用。打開時鐘應用 並選擇鬧鈴界面的第一個鬧鐘設置,修改該設置的開關。然後返回到時鐘界面再進入倒計時界面。

package com.uia.example.my;

import android.widget.ListView;
import android.widget.Switch;

import com.android.uiautomator.core.UiObject;
import com.android.uiautomator.core.UiObjectNotFoundException;
import com.android.uiautomator.core.UiScrollable;
import com.android.uiautomator.core.UiSelector;
import com.android.uiautomator.testrunner.UiAutomatorTestCase;

public class LaunchSettings extends UiAutomatorTestCase {

// TODO 重要注意: 在運行該測試代碼的時候 需要先把手機語言環境設置爲英文。
public void testDemo() throws UiObjectNotFoundException {

    // 模擬 HOME 鍵點擊事件
    getUiDevice().pressHome();

    // 現在打開了主屏應用,模擬點擊所有應用按鈕操作來啓動所有應用界面。
    // 如果你使用了uiautomatorviewer來查看主屏,則可以發現“所有應用”按鈕的
    // content-description 屬性爲“Apps”。可以使用該屬性來找到該按鈕。
    UiObject allAppsButton = new UiObject(new UiSelector().description("Apps"));

    // 模擬點擊所有應用按鈕,並等待所有應用界面起來
    allAppsButton.clickAndWaitForNewWindow();

    // 在所有應用界面,時鐘應用位於Apps tab界面中。下面模擬用戶點擊Apps tab操作。
    // 找到 Apps tab 按鈕
    UiObject appsTab = new UiObject(new UiSelector().text("Apps"));

    // 模擬點擊 Apps tab.
    appsTab.click();

    // 然後在 Apps tab界面,模擬用戶滑動到時鐘應用的操作。
    // 由於Apps界面是可以滾動的,所有用
    // UiScrollable 對象.
    UiScrollable appViews = new UiScrollable(new UiSelector().scrollable(true));

    // 設置滾動模式爲水平滾動(默認爲垂直滾動)
    appViews.setAsHorizontalList();

    if (allAppsButton.exists() && allAppsButton.isEnabled()) {
        // allAppsButton在當前界面已經不可見了 所以這裏不會執行
        allAppsButton.click();
    }
    // 查找時鐘應用並點擊
    UiObject settingsApp = appViews.getChildByText(
            new UiSelector().className(android.widget.TextView.class.getName()), "Clock");
    settingsApp.clickAndWaitForNewWindow();

    // 驗證當前顯示 的應用包名爲時鐘

    UiObject settingsValidation = new UiObject(new UiSelector().packageName("com.google.android.deskclock"));
    // 如果不存在則出錯提示
    assertTrue("Unable to detect Clock", settingsValidation.exists());

    // 模擬點擊時間tab
    UiObject clock = new UiObject(new UiSelector().description("Clock"));
    clock.clickAndWaitForNewWindow();
    // 模擬點擊下方的鬧鐘圖標
    UiObject alarms = new UiObject(new UiSelector().description("Alarms"));
    alarms.clickAndWaitForNewWindow();

    UiScrollable list = new UiScrollable(new UiSelector().className(ListView.class.getName()));
    if (list.getChildCount() > 0) {
        UiObject listIndex0 = list.getChild(new UiSelector().index(0));
        UiObject switchBtn = listIndex0.getChild(new UiSelector().className(Switch.class.getName()));

        boolean isChecked = switchBtn.isChecked();

        switchBtn.click();
    }
    // 模擬點擊返回鍵
    getUiDevice().pressBack();

    UiObject timer = new UiObject(new UiSelector().description("Timer"));
    timer.clickAndWaitForNewWindow();

}

}

打包測試代碼並在測試機上運行

如下步驟打包測試代碼並在測試機運行的步驟:

1.創建打包測試代碼的Build腳本。通過如下命令來生成Build腳本:

<android-sdk>/tools/android create uitest-project -n <name> -t 1 -p <path>

是包含測試代碼的項目名稱,是包含測試代碼的項目文件路徑。-t後面的1是Android sdk版本id。

注意: 在創建Build腳本之前,已經創建好了測試項目並編寫好了測試代碼。只不過該測試項目還沒有包含打包腳本所以無法打包運行。在創建Build腳本的時候,屬性就是測試項目的名稱、就是已經創建的測試項目在電腦中的文件夾路徑。 如果電腦上安裝了多個版本的Android sdk,則需要運行/tools/android list target 來查看每個SDK的id。選擇4.1以上的id即可。

  1. 設置ANDROID_HOME 環境變量。

Windows:set ANDROID_HOME=

Unix:export ANDROID_HOME=

  1. 打開命令行創建,導航到第一步中的目錄中,運行 ant build 來打包。

  2. 通過adb push命令把上一步打包出來的jar文件複製到測試手機中。

    adb push /bin/.jar /data/local/tmp/

    類似如下代碼:

    adb push ~/dev/workspace/LaunchSettings/bin/LaunchSettings.jar /data/local/tmp/

運行uiautomator 測試
下面是運行 LaunchSettings.jar jar包中測試代碼的命令。測試代碼位於com.uia.example.my包中。

adb shell uiautomator runtest LaunchSettings.jar -c com.uia.example.my.LaunchSettings

關於uiautomator 的更多信息參考這裏:http://developer.android.com/tools/help/uiautomator/index.html
最佳實踐

下面是一些使用uiautomator 做UI測試的最佳實踐

在待測應用可能運行的儘可能多的設備上跑uiautomator 測試。例如 在不同的屏幕密度、不同的屏幕尺寸上運行測試。
還應該在一些常規場景下測試UI,例如 電話打入情況、網絡連接斷開的情況等。
發佈了53 篇原創文章 · 獲贊 93 · 訪問量 26萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章