一,uiautomatorviewer是什么?
Android 4.1發布的,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
二,uiautomatorviewer的工作流程
- 安裝要測試的應用到手機中,分析應用的UI界面元素 並確保被測試應用的各個控件可以被測試工具獲取到。
- 創建知道測試案例來模擬應用中的用戶操作步驟。
- 編譯測試案例代碼為Jar包並復制該Jar包到安裝了待測應用的測試手機中。
- 運行測試並查看結果
- 修改任何發現的bug,然后修復並重新測試。
三,分析待測應用的UI元素
在開始編寫測試案例代碼之前,需要熟悉待測應用的UI元素。可以通過uiautomatorviewer 工具來獲取應用的界面截圖並分析。uiautomatorviewer 工具提供了一個便利的方式來查看UI布局結構,並且可以查看各個控件的相關屬性。利用這些信息可以用來創建UI測試代碼。
分析待測程序的UI組件的步驟:
1. 將android設備連接到有開發環境機器上
2. 打開命令行終端窗口,進入android sdk tool所在目錄
3. 運行以下命令:
$ uiautomatorviewer
4. 捕獲到待分析的界面后,點擊設備快照“Device Screenshot”按鈕
注意:如果你連接了多個設備,需要指定ANDROID_SERIAL 環境變量,來說明對哪個設備進行截屏:
a. 運行以下命令,找到你的設備序列號
$ adb devices
b. 設置環境變量ANDROID_SERIAL
在windows上:
set ANDROID_SERIAL=<device serial number>
在unix上:
export ANDROID_SERIAL=<device serial number>
如果你只連接一個設備,則不需要設置
5. 查看應用的UI屬性
a. 在快照的左側面板上,可以看到uiautomatorviewer顯示的UI組件;在右側,下邊是組件的屬性,上邊是布局的層次
b. 你也可以點擊”Toggle NAF Nodes“按鈕,來顯示uiautomator框架無法訪問的UI組件。對於那些組件,只有有限的屬性信息可以供uiautomator使用。
測試准備工作
在開始使用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如下圖:
如果你不使用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>
<name>是包含測試代碼的項目名稱,<path>是包含測試代碼的項目文件路徑。-t后面的1是Android sdk版本id。
注意: 在創建Build腳本之前,已經創建好了測試項目並編寫好了測試代碼。只不過該測試項目還沒有包含打包腳本所以無法打包運行。在創建Build腳本的時候,<name>屬性就是測試項目的名稱、<path>就是已經創建的測試項目在電腦中的文件夾路徑。 如果電腦上安裝了多個版本的Android sdk,則需要運行/tools/android list target 來查看每個SDK的id。選擇4.1以上的id即可。
2. 設置ANDROID_HOME 環境變量。
Windows:set ANDROID_HOME=
Unix:export ANDROID_HOME=
3. 打開命令行創建,導航到第一步中的目錄中,運行 ant build 來打包。
4. 通過adb push命令把上一步打包出來的jar文件復制到測試手機中。
adb push <path>/bin/<name>.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,例如 電話打入情況、網絡連接斷開的情況等。