Hot to use UiAutomator testing anything ?
轉載請註明出處:https://medium.com/@devwilly,違者必究
尋找一套適合的自動化測試工具是一件非常難的事情,我們都希望一套工具就能解決所有的問題,但結果總是不如想像中的容易。Android生態系中其實有蠻多套測試相關的工具,如:Robotium、Expresso、UiAutomator、Appium。
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 屬於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-id
或class
作為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
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在背景、驗證過程畫面被中斷等問題,想解決這些問題可使用UiWatcher。
操作步驟如下:
(1) 點擊Launcher 上的Facebook App icon
(2) 點擊「搜尋」欄位
(3) 輸入「KKBOX」並點擊 Keyboard 上的Enter按鈕
(4) 尋找「KKBOX」粉絲頁並點擊它
(5) 進入粉絲頁後,尋找「貼文」Tab 並點擊它
(6) 尋找待驗證的App Links連結
(8) 導向指定頁面後,確認該頁面是否為預期畫面
測試結果:
實作方法:
Gradle Test:
./gradlew connectedDebugAndroidTest — info — stacktrace
測試報告存放位置:
../ your project /app/build/reports/androidTests/connected
Conclusion
由於UI變動快速且UI Auto Testing算是非常難實作的區塊,一直以來就較少人將資源投資在這邊,因為效益普遍偏低。
UiAutomator 和 Espresso 兩套都算是蠻適合投資的工具,它能適時幫助測試人員解決一些重複性的工作。
若你喜歡這篇文章歡迎推薦給你的朋友
若你喜歡我的部落格歡迎追隨我
Reference
轉載請註明出處:https://medium.com/@devwilly,違者必究