一、簡介
android sdk api 16開始,Android SDK開始支持兩個做功能UI測試的新工具。
(1)uiautomatorviewer,用以掃描以及分析Android應用程序的UI部件的工具。
(2)uiautomator ,提供API用以自定義UI測試的Java庫。
要應用上面兩個工具,除了需要android sdkapi 16以上的前提條件外,還要求Android SDK Tools爲21版以上。
優點:1.可以對所有操作進行自動化,操作簡單;
2.不需要對被測程序進行重簽名,且,可以測試所有設備上的程序,比如~某APP,比如~撥號,比如~發信息等等
3.對於控件定位,要比robotium簡單一點點
缺點:1.uiautomator需要android level 16以上纔可以使用,因爲在level 16及以上的API裏面才帶有uiautomator工具
2.如果想要使用resource-id定位控件,則需要level 18及以上纔可以
3.對中文支持不好(不代表不支持,第三方jar可以實現)
二、常用API
UiAutomator主要涉及一下幾個類,大多數位於源碼包的com.android.uiautomator.core下,以下幾個類是平時在寫腳本中用的最多的:UiDevice UiSelector UiScrollable UiObjec UiCollection
每個測試用例都需要繼承UiAutomatorTestCase,以實現測試環境的setup,teardown等。而UiAutomatorTestCase則是通過繼承Junit3中的TestCase類,並在其中的setUp() 、tearDown() 、getParams()函數中。其中主要是用Bundle實現Android Activity之間的通訊。在UiAutomatorTestCase,還加入了getUiDevice()等關於UiDevice的函數,以實現在測試的任意地方均可調用UiDevice()。
(一)UiDevice:用與訪問有關設備狀態的信息,也可以使用這個類來模擬用戶在設備上的操作。
可以通過下面的方法得到實例: UiDevice mdevice= getUiDevice();
l 獲取座標參數
函數返回值 |
函數體 |
說明 |
實例 |
boolean |
click(int x, int y) |
模擬用戶在指定位置點擊 |
mdevice.click(200, 300) 點擊屏幕的200,300座標處 |
int |
getDisplayHeight() |
獲得當前設備的屏幕分辨率的高 |
例如,我的手機1920*1080,得到的是 1920 |
int |
getDisplayWighth() |
獲得當前設備的屏幕分辨率的寬 |
例如,我的手機1920*1080,得到的是 1080 |
point |
getDisplaySizeDp() |
獲取顯示尺寸大小 |
|
l 系統信息
函數返回值 |
函數體 |
說明 |
實例 |
String |
getCurrentActivityName() |
獲得的是應用程序在桌面上顯示的名字 |
例如,在qq首頁得到的是“QQ”,在微信登錄頁得到的是“微信”,注意,這個得到的不是Activity的名字 |
String |
getCurrentPackageName() |
獲得當前顯示的應用程序的包名 |
例如,在微信啓動的時候,獲得的是“com.tencent.mm” |
l 滑動、拖拽
函數返回值 |
函數體 |
說明 |
實例 |
boolean |
swipe(int startX, int startY, int endX, int endY, int steps) |
用指定的步長,從A點滑動B點 |
例如,需要從(10, 10)點用兩步滑動到(100, 200)點,則需要mdevice.swipe(10, 10, 100, 200, 2) |
boolean |
drag(startX, startY, endX, endY, steps) |
拖拽坐標處對象到另一個坐標 |
|
boolean |
swipe(segments, segmentSteps) |
在Points[]中以segmentSteps滑動 |
|
l 系統按鍵
函數返回值 |
函數體 |
說明 |
實例 |
boolean |
isScreenOn() |
判斷手機當前是否滅屏 |
當手機滅屏的時候,得到是“false”,手機亮屏,得到的是“true” |
void |
wakeUp() |
點亮當前屏幕 |
調用後,相當於按下了電源鍵,如果手機設置了滑動鎖屏,滑動鎖屏還是在的,不會自動解開 |
boolean |
pressBack() |
點擊back鍵 |
|
boolean |
pressHome() |
點擊home鍵 |
|
boolean |
pressMenu() |
點擊menu鍵 |
|
boolean |
pressKeyCode(int keyCode) |
利用keycode值模擬一次按下事件 |
例如,需要按下數字1 數字1的keycode是 KEYCODE_NUMPAD_1,更多keycode可以在 http://developer.android.com/intl/zh-cn/reference/android/view/KeyEvent.html 進行查詢 |
void |
unfreezeRotation() |
啓用傳感器,並允許旋轉 |
|
boolean |
takeScreenshot(File storePath) |
截取當前屏幕,保存到文件 |
例如,File files = new File("/sdcard/res.jpg"); mdevice.takeScreenshot(files); 即可將截圖保存到sd卡中了。 |
l 等待窗口
函數返回值 |
函數體 |
說明 |
void |
waitForIdle() |
等待當前窗口處於空閒狀態、默認10s |
void |
waitForIdle(long timeout) |
自定義超時等待當前窗口處於空閒狀態 |
void |
waitForWindowUpdate(packageName, timeout) |
等待窗口內容更新 |
(二)UiSelector:按照一定的條件(例如控件的text值,資源id),定位界面上的元素。如果一個條件無法定位,那麼可以通過多個條件組合,來定位一個元素。如果發現多個滿足條件的控件則會返回第一個控件。在構造UiSelector的時候可以 組合使用多個屬性來定位具體的控件。如果沒有找到控件則會拋出 UiAutomatorObjectNotFoundException 異常。UiSelector對象的最終目的是去構造一個UiObject對象。
l 根據text構造
函數返回值 |
函數體 |
說明 |
實例 |
UiSelector |
text(String text) |
根據“控件text屬性的內容”構造出UiSelector對象 |
一個控件text的值是“發現”,UiSelector s = new UiSelector().text("發現"); |
UiSelector |
textContains(String text) |
根據“控件text屬性包含的內容”構造出UiSelector對象 |
同上例子:UiSelector s = new UiSelector().textContains("現"); |
UiSelector |
textMatches(String regex) |
根據“控件text屬性正則表達式的內容”構造出UiSelector對象 |
正則表達式語法參考網上資料即可。 |
UiSelector |
textStartsWith(String text) |
根據“控件text屬性開始的內容”構造出UiSelector對象 |
同上例子:UiSelector s = new UiSelector().textStartsWith("發"); |
比較常用,準確度也比較高,中文查找的時候,如果遇到 “UiOjbectNotFoundException”的時候,記得把項目的編碼格式改爲utf-8。
l 根據description構造
函數返回值 |
函數體 |
說明 |
實例 |
UiSelector |
description(String desc) |
根據“控件content-desc屬性的內容”構造出UiSelector對象 |
一個控件text的值是“發現”,UiSelector s = new UiSelector().text"發現("); |
UiSelector |
descriptionContains(String desc) |
包含** |
同上例子:UiSelector s = new UiSelector().textContains("現"); |
UiSelector |
descriptionMatches(String regex) |
正則 |
正則表達式語法參考網上資料即可。 |
UiSelector |
descriptionStartsWith(String desc) |
以**開始 |
同上例子:UiSelector s = new UiSelector().textStartsWith("發"); |
l 根據資源id
函數返回值 |
函數體 |
說明 |
iSelector |
resourceId(String id) |
根據資源id獲取對象,例如:UiSelector s = new UiSelector().resourceId("com.tencent.mm:id/b8m") |
UiSelector |
resourceIdMatches(String regex) |
根據資源id的正則表達式獲取對象 |
如果父類下面的子類有相同的resource-id,則可以通過instance(?)來判定,比較常用
• 根據類class
(1)UiSelector className(String className):根據控件的類名來找到UiSelector對象。
(2)UiSelector s = newUiSelector().className("android.widget.TextView").instance(1);獲得相同類名下的第2個對象index(index)與instance(instance)類似
(3)UiSelector childSelector(UiSelector selector):有的時候子控件不好獲得,而其父控件比較好獲得的時候:
先得到父控件:UiSelectors_p = new UiSelector().resourceId("com.tencent.mm:id/axj");
其次 UiSelectors_c= s_p.childSelector( newUiSelector().className("android.widget.EditText") );
在它的父控件的childSelector方法中傳入一個帶有一定特徵的UiSelector對象,即可得到子控件。
(4)UiSelector fromParent(UiSelector selector):父控件不好獲得,而是同級的控件(同屬一個parent)比較好獲取
先得到同級的UiSelector對象:UiSelector s1 = new UiSelector().resourceId("com.tencent.mm:id/axc");
再得到和它同樣一個父控件的ImageView的UiSelector對象:UiSelector s2 = fromParent( newUiSelector().className("android.widget.ImageView") );
(三)UiObject:UiObject是UiAutomator的核心屬性之一。它代表了整個UI界面中的所有對象元素。 它的功能包括:獲取UI元素,點擊、拖拽、滑動、對象屬性判斷、手勢等。通過UiSelector來查找UiObject。
函數返回值 |
函數體 |
說明 |
boolean |
click() |
點擊對象 |
boolean |
clickAndWaitForNewWindow() |
點擊對象並等待新窗口出現 |
boolean |
clickAndWaitForNewWindow(timeout) |
點擊對象並等待新窗口出現,指定延遲 |
boolean |
longClick() |
長按對象 |
boolean |
dragTo(destX, destY, steps) |
以steps拖動對象到座標 |
boolean |
swipeDown(steps) |
向下拖動 |
boolean |
setText(text) |
設置內容爲text |
boolean |
clearTextField() |
清除文本 |
boolean |
isCheckable() |
獲取對象checkable狀態 |
boolean |
waitForExists(timeout) |
等待對象出現 |
boolean |
exists() |
對象是否存在 |
(四)UiScrollable:代表可滾動的控件。可以用UiScrollable來模擬水平或者垂直滾動的UI元素。如果需要操作的元素在屏幕外需要滾動屏幕才能看到的情況下需要使用UiScrollable
(五)UICollection:通常用於獲取滿足某種搜索條件的組件集合,通過鏈式搜索確定最終需要的組件。 先按照一定的條件枚舉容器內的子元素,再從符合條件的子元素中進一步定位。 一般使用容器類組件作爲父類,用於尋找不好定位的子元素。代表控件的集合。獲取UiCollection的方式和UiObject一樣,通過 UiSelector查找。 UiCollection對應Android系統中的ViewGroup以及子控件。
(六)UIWatcher:通常我們會讓腳本來按照我們所需要的順序來執行,但有時候短信、電話來了,打斷了腳本的執行。 所以,我們的腳本必須要有一定的容錯性。UiWatcher正是這樣一個容錯的對象,當我們在順序執行腳本時,如果中間突然插入了一些不明事件,我們可以使用UiWatcher來攔截異常,處理完異常後,再返回原來的腳本執行順序。經常用來處理一些意外事件,如彈窗等。
(七)Configuration:對默認操作的配置,通常情況下,我們使用默認的Configuration就足夠了,當然,如果你有一些特殊需求,就可以通過Configuration類來設置。它能更改我們前面提到的所有默認屬性的設置。包括默認延遲、輸入延遲、等待超時等等。
三、查看測試報告
下面是一個典型的UiAutomator測試報告:
INSTRUMENTATION_STATUS:numtests=1
INSTRUMENTATION_STATUS: stream=
com.hj.autotest.AutoTest:
INSTRUMENTATION_STATUS: id=UiAutomatorTestRunner
INSTRUMENTATION_STATUS:test=testDevice
INSTRUMENTATION_STATUS:class="com".hj.autotest.AutoTest
INSTRUMENTATION_STATUS:current=1
INSTRUMENTATION_STATUS_CODE: 1
INSTRUMENTATION_STATUS:numtests=1
INSTRUMENTATION_STATUS:stream=.
INSTRUMENTATION_STATUS:id=UiAutomatorTestRunner
INSTRUMENTATION_STATUS:test=testDevice
INSTRUMENTATION_STATUS:class="com".hj.autotest.AutoTest
INSTRUMENTATION_STATUS:current=1
INSTRUMENTATION_STATUS_CODE: 0
INSTRUMENTATION_STATUS: stream=
Test results forWatcherResultPrinter=.
Time: 31.489
OK (1 test)
INSTRUMENTATION_STATUS_CODE: -1
這些報告被INSTRUMENTATION_STATUS_CODE分爲了三個部分,1表示運行前,-1表示運行完成。如果出錯了,可以在報告中找到相應的錯誤信息。同樣需要知道的是,UiAutomator也是JUnit工程,同樣可以在裏面使用斷言來進行某些變量、結果值的測試,這些同樣會在報告中體現出來。
current:當前運行的測試順序編號,故和方法名有關
class:當前運行方法所在類的類名
numtests:測試總數,一個publictestXXX方法就是一個測試
test:當前測試的方法名
INSTRUMENTATION_STATUS_CODE:測試狀態碼,一般1是正在測試,0是測試通過,-1是錯誤