Hot to use UiAutomator testing anything ?

Willy Chang
15 min readApr 17, 2017

--

轉載請註明出處:https://medium.com/@devwilly,違者必究

尋找一套適合的自動化測試工具是一件非常難的事情,我們都希望一套工具就能解決所有的問題,但結果總是不如想像中的容易。Android生態系中其實有蠻多套測試相關的工具,如:RobotiumExpressoUiAutomator、Appium。

來源:https://martinfowler.com/bliki/TestPyramid.html

What’s UiAutomator ?

UI Automator is a UI testing framework suitable for cross-app functional UI testing across system and installed apps.

簡單來說UiAutomator是隨著Android一起推出的UI測試工具,它不僅支援所有Android裝置上的事件操作且無需依賴元件座標就能完成測項驗證。

UiAutomator相較於其他UI測試工具優缺點呢?

優點:跨App測試、易上手學習成本低、Google自家推出的工具、裝置上的操作幾乎都能支援

缺點:Android 4.x以上手機才能使用、不支援App內WebView操作驗證

How to use UiAutomator ?

使用UiAutomator必需搭配UiAutomator Viewer一起使用,可利用它來查看畫面階層關係各個畫面的詳細資訊

UiAutomator Viewer

UiAutomator Viewer 屬於Android SDK tools,基本上若你是Android的開發者,就不用重新下載檔案

UiAutomator Viewer檔案位置: ../find-your-sdk-file/tools

How to use UiAutomator Viewer ?

此SDK tools對實體手機模擬器皆都能支援,以下將針對較常使用的功能進行說明,若有不懂的地方歡迎提問。

A:截取手機或模擬器目前最新資訊

B:截取完成後,可藉由畫面來尋找元件內容

C:元件詳細資訊,最常使用的資訊有下面幾點

  • text:畫面上實際顯示的內容
  • resource-id:以上圖為例,resource id為user_profile_pager
  • class:元件類別(如:ViewPager、RecyclerView、……)
  • package:your testing app package name
  • content-desc:畫面上不會顯示出來的內容,通常用於視障輔助軟體辨別。

D:手機或模擬器實際畫面

建議使用resource-idclass 作為UiAutomator判讀方式,因為這兩種屬性通常較少變動

How to use those UiAutomator component object ?

接下來將針對UiAutomator內的元件進行詳細介紹,若有不懂的地方歡迎提問!!

Start from Gradle

首先需要指定 Instrumentation Runner 來幫助執行所有的測試項目並回傳測試結果。

android {
defaultConfig {
...
testInstrumentationRunner
"android.support.test.runner.AndroidJUnitRunner"
}
}
dependencies {
...
androidTestCompile 'com.android.support.test:runner:0.5'
androidTestCompile 'com.android.support.test:rules:0.5'
androidTestCompile
'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
androidTestCompile
'com.android.support:support-annotations:25.3.0'
testCompile 'junit:junit:4.12'
}

UiDevice

提供裝置相關的狀態內容,也能利用它來模擬使用者實際操作的行為,如:按下Home鍵、Back鍵、電源鍵等等。

接著使用getInstance()取得UiDevice相關資訊,以下針對幾種較常用的方法進行詳細說明

private UiDevice getUiDevice() {
return UiDevice
.getInstance(InstrumentationRegistry.getInstrumentation());
}

findObject(BySelector selector):尋找某個物件(BySelector)

findObject(UiSelector selector):尋找某個物件(UiSelector)

getCurrentPackageName():取得目前頁面的package name

pressBack ():回上一頁

pressHome ():按Home鍵

pressKeyCode(int keyCode):模擬鍵盤輸入,詳情請參考KeyEvent

sleep ():模擬按電源鍵,關掉螢幕

wakeUp ():模擬按電源鍵,開啟螢幕

isScreenOn ():檢查螢幕是否開啟

takeScreenshot (File storePath):截取畫面並儲存到指定路徑中

getUiDevice().pressHome();
getUiDevice().pressBack();
getUiDevice().pressKeyCode(KeyEvent.KEYCODE_W);
getUiDevice().pressKeyCode(KeyEvent.KEYCODE_I);
getUiDevice().pressKeyCode(KeyEvent.KEYCODE_L);
getUiDevice().pressKeyCode(KeyEvent.KEYCODE_L);
getUiDevice().pressKeyCode(KeyEvent.KEYCODE_Y);
getUiDevice().takeScreenshot(new File("/sdcard/test1.png"));if (getUiDevice().isScreenOn()) {
getUiDevice().sleep();
} else {
getUiDevice().wakeUp();
}

UiObject | UiObject2

UiObject代表一個元件對象,它提供一系列的方法和屬性來模擬手機上的實際操作,如:物件點擊、長按、拖動、滑動等等,另外UiAutomator2中導入了UiObject2,其內容與UiObject差別不大。

以下是我比較長使用到的UiObject屬性

click():點擊物件

clickAndWaitForNewWindow (long timeout):點擊物件並等待新頁面出現

clickAndWaitForNewWindow ():點擊物件並等待新頁面出現

getChild (UiSelector selector):從present UiObject中取的新的child物件

getChildCount ():取得子元件數量

setText (String text)

clearTextField:清除元件上內容,例如:EditText

isSelected ():元件屬性

isChecked ():元件屬性

isCheckable ():元件屬性

isEnabled ():元件屬性

isClickable ():元件屬性

isScrollable ():元件屬性

exists ():元件屬性

waitForExists (long timeout):等待某個元件出現

由於 UiObject2 與 UiObject 差異性不大,以下只列出幾種較為特別的方法

clickAndWait (EventCondition<R> condition, long timeout):點擊並等待某個事件

wait (UiObject2Condition<R> condition, long timeout):等待某條件被滿足

元件屬性

UiSelector | BySelector | By

UiSelector:一種搜尋條件,可在當前頁面中查詢和取得特定元素且利用它建立ui物件。

className (String className)

description (String desc)

fromParent (UiSelector selector)

index (int index)

packageName (String name)

resourceId (String id)

scrollable (boolean val)

BySelector:與UiSelector類似,也是利用指定的搜尋條件來取得相對的UI元件。

By:is a utility class which enables the creation of BySelectors in a concise manner

clazz (String packageName, String className)

desc (String contentDescription)

hasChild(BySelector childSelector)

pkg(Pattern applicationPackage)

res(String resourcePackage, String resourceId)

text(String textValue)

若我想開啟「Medium」的App,以下三種作法都能達到一樣的效果

UiObject obj = new UiObject(new UiSelector().text("Medium"));
obj.click();

UiObject obj1 = getUiDevice().findObject(new UiSelector().text("Medium"));
obj1.click();

UiObject2 obj2 = getUiDevice().findObject(By.text("Medium"));
obj2.click();

UiCollection

屬於UiObject的子類別,從已符合條件容器中再次利用搜尋條件來進行子元素搜尋。

getChildByDescription (UiSelector childPattern, String text)

getChildByText (UiSelector childPattern, String text)

UiScrollable

UiScrollable 繼承了 UiCollection,它提供各種滾動事件處理的方法。

getChildByDescription (UiSelector childPattern, String text, boolean allowScrollSearch):是否允許滾動且查詢UiSelector條件集合後再利用文案來尋找子元素

getChildByText (UiSelector childPattern, String text, boolean allowScrollSearch)

scrollBackward ()

scrollIntoView (UiSelector selector)

Sample

以下將用KKBOX當作範例並使用UiAutomator 來驗證 What is Deep linking and App Links 實作方式。

首先你必需知道App Links的兩大功能:

  • 有安裝,開啟App並導向指定頁面
  • 沒安裝,導向Google Play安裝App

接著我們先驗證沒安裝KKBOX App時點擊App Links的行為是否正確

Setting build.gradle

build.gradle 設定檔

Non Install App Testing

操作步驟如下:
(1) 點擊Launcher 上的Facebook App icon
(2) 點擊「搜尋」欄位
(3) 輸入「KKBOX」並點擊 Keyboard 上的Enter按鈕
(4) 尋找「KKBOX」粉絲頁並點擊它
(5) 進入粉絲頁後,尋找「貼文」Tab 並點擊它
(6) 尋找待驗證的App Links連結
(7) 當跳出App Links 導安裝Dialog時,點擊「安裝」按鈕
(8) 導向Google Play成功後,點擊安裝進行KKBOX App 安裝

測試結果:(每隻手機對於UI Testing略有不同,可能需要微調程式碼)

沒安裝App時, 點擊App Links連結並導向Google Play下載KKBOX App

實作方法:

以下方法是最簡單的驗證方式,其並無考慮意外狀態,如App在背景、驗證過程畫面被中斷等問題,想解決這些問題可使用UiWatcher

App Links not install app testing

Installed Testing

步驟與Non Install App 差不多,最大的差異是導向指定App後需要如何驗證此頁面是正確的,以下範例忽略幾種狀況:

  • 首次安裝需開啟Permission(可使用UiWatcher 解決)
KKBOX權限確認
KKBOX 登入頁面

操作步驟如下:
(1) 點擊Launcher 上的Facebook App icon
(2) 點擊「搜尋」欄位
(3) 輸入「KKBOX」並點擊 Keyboard 上的Enter按鈕
(4) 尋找「KKBOX」粉絲頁並點擊它
(5) 進入粉絲頁後,尋找「貼文」Tab 並點擊它
(6) 尋找待驗證的App Links連結
(8) 導向指定頁面後,確認該頁面是否為預期畫面

驗證內容

測試結果:

有安裝App時, 點擊App Links連結並導向指定頁面

實作方法:

Gradle Test:

./gradlew connectedDebugAndroidTest — info — stacktrace

測試報告存放位置:

../ your project /app/build/reports/androidTests/connected

Conclusion

由於UI變動快速且UI Auto Testing算是非常難實作的區塊,一直以來就較少人將資源投資在這邊,因為效益普遍偏低。

UiAutomator 和 Espresso 兩套都算是蠻適合投資的工具,它能適時幫助測試人員解決一些重複性的工作。

若你喜歡這篇文章歡迎推薦給你的朋友

若你喜歡我的部落格歡迎追隨我

--

--