除了針對 Android 應用程序中的組件(諸如:Activty,Service,content provider)進行單元測試以外,在運行時對其用戶接口(UI)的行爲進行測試也很重要。UI 測似確保應用程序有正確的的 UI 輸出來響應用戶一系列的操做,好比一個按鍵輸入或者按工具條,菜單,對話框,圖片和其它 UI 操做。html
功能測試或者黑盒 UI 測試並不須要測試人員知道應用的內部實現細節,只需知道當用戶執行某些操做或者進行某種輸入時的輸出便可。這種方法有利於分離團隊中測試人員和開發人員的職責。java
普通的 UI 測試方法就是手工運行測試並驗證應用程序的行爲是否符合預期。可是這種方法既沉悶又耗時還容易出現偏差。更高效更可靠的方法是用測試框架軟件進行 UI 自動化測試。自動化測試建立代碼來執行測試任務(test case),測試任務覆蓋各類使用場景,這樣測試框架就能夠以一種可重複的方式自動運行這些 test case。android
Overview程序員
Android SDK 提供了下面兩個工具,來對你的應用程序進行自動化功能測試:shell
使用這兩個工具必須安裝下面兩個版本的 Android 開發工具:app
Workflow for the the uiautomator testing framework框架
Analyzing Your Application’s UIide
在開始寫 test case 以前,這有助於咱們熟悉待測應用的 UI 組件(包括 View 和控制)。對於鏈接開發電腦上的任何 Android 設備,咱們能夠用 uiautomatorviewer 工具對其前臺 UI 進行截屏。該工具提供一個方便的可視化界面,用於查看其佈局層次以及 View 的屬性。利用這些信息,咱們接下來就能夠建立 uiautomator 測試代碼了。函數
對待測應用程序的 UI 組件進行分析:工具
1.鏈接 Android 設備和開發電腦。
2.打開命令行窗口併到 <android-sdk>/tools/ 目錄下
3.用下面命令運行該工具:
$ uiautomatorviewer
4.點擊 uiautomatorviewer 圖形界面上的 Device Screenshot 按鈕截屏用於分析。
注意:若是你的電腦上連了多個設備,能夠經過設置 ANDROID_SERIAL 環境變量來區分它們:
a.用下面命令查看鏈接設備的 serial numbers:
$ adb devices
b.經過設置 ANDROID_SEIAL 來選擇一個設備用於測試:
Windows:
set ANDROID_SERIAL=<device serial number>
UNIX:
export ANDROID_SERIAL=<device serial number>
若是你只連了一個設備就不須要設置該值。
5.查看應用程序總 UI 屬性:
Preparing to Test
在開始使用 uiautomator 測試框架以前,須要完成下面的準備工做:
Load the application to a device
若是你正在閱讀該文檔,極可能待測 Android 應用程序還沒有發佈。若是你有 apk 文件的拷貝,就能夠經過 adb 工具把它安裝到測試設備上去,如何用 adb 工具安裝 APK 文件,請參考 adb 文檔。
Identify the application’s UI components
在寫 uiatomator 測試以前,首先要識別待測應用程序的 UI 組件。一般優秀應用的 UI 組件是可見的而且能夠和用戶交互的。UI 組件應該有可見的 text 標籤或者 android:contentDescription 屬性,或者二者兼具。
咱們能夠用 uiautomatorviewer 工具方便地查看待測應用中可見的屏幕對象(UI 組件)。至於如何經過該工具來分析一個應用程序的屏幕信息,請參考 Analyzing Your Application’s UI 部分。關於 Android 提供了那些經常使用的 UI 組件,請參考 User Interface。
Ensure that the application is accessible
這一步,是由於 uiautomator 工具運行你的 UI 功能測試代碼依賴於 Android 框架支持輔助功能的特性。要使用 uiautomator 工具,至少應該知足一下條件:
android:hint
attribute with any graphical icons used by controls that provide feedback to the user (for example, status or state information).關於實現、測試可訪問性的更多信息,請參考 Making Applications Accessible。
通常狀況下,經由 View 和 ViewGroup 類,Android 程序員能夠輕易對輔助功能進行支持。可是有些應用使用自定義 view 組件以提供更好的用戶體驗。而這些自定義組件並無從標註 的 Android UI 組件那裏繼承到對輔助功能的支持。若是你的應用程序屬於這種狀況,請經過實現 AccessibilityNodeProvider 類來確保 Android 的輔助服務能夠訪問自定義 UI 組件。關於如何使自定義控件支持輔助功能,請參考 Making Applications Accessible。
Configure your development environment
若是你用 Eclipse 作開發,Android SDK 另外提供了工具來幫助你編寫 uiautomator test case 並打包 jar 文件。要設置 Eclipse 以使用這些工具,須要建立一個包含 uiautomator 客戶端庫的工程,該庫通常和 Android SDK 庫在一塊兒。配置 Eclipse:
a. 點擊 Add Library > JUit,而後選擇 JUnit3。
b. 點擊 Add External JARs… 進入 SDK 目錄,在 platforms 目錄下,選擇最新版本的 SDK目錄,並選擇 uiautomator.jar 和 android.jar 文件。
若是你不使用 Eclipse 作開發環境,請確保你的 Java class path 包括了 <android-sdk>/platforms/<sdk> 目錄下的 uiautomator.jar 和 android.jar 文件。
這些準備工做完成後,立刻就能夠建立 uiautomator 測試了。
Creating uiautomator Tests
要構建一個能夠在 uiautomator 框架中運行的測試,首選要建立一個繼承自 UiAutomatorTestCase 的類。在 Eclipse 中這個 test case 文件屬於工程的 src 目錄。而後,會把這個 test case 構建成一個 JAR 文件,最後把這個 JAR 文件複製到測試設備中。這個 JAR 文件並非一個 APK 文件,而且和待測應用是分離的。
由於 UiAutomatorTestCase 類繼承自 junit.framework.TestCase,因此你能夠用 JUnit 的 Assert 類來測試待測應用中的 UI 組件,看是否返回指望結果。要學習更多的 JUnit 知識,你能夠閱讀 junit.org 主頁中的文檔。
test case 的首要任務是將要訪問安裝了待測應用程序的設備。先對設備的 Home screen 作測試來練練手也是一個不錯的選擇。對於 Home Screen(或者待測應用的其它位置),你能夠用 uiautomator 提供的 API 來模擬用戶的操做對特定的 UI 組件進行測試。至於如何組織一個 uiautomator test case 請看 sample test case 部分。
uiautomator API
uiautomator API 在 <android-sdk>/platforms/ uiautomator.jar 文件中,該 API 中包含如下幾個關鍵類,經過這些類咱們能夠捕獲、操做待測應用中的 UI 組件:
UiDevice
表明了設備的狀態。在測試代碼中,能夠調用 UiDevice 實例中的函數來檢測設備的各類屬性狀態,例如當前的屏幕的方向或者尺寸。也能夠經過 UiDevice 實例來執行設備層次的操做,好比強制改變設備的方向,按下 d-pad 物理按鍵或者 Home 建和菜單按鈕。
下面代碼就是獲取 UiDevice 實例,而後按下 Home 鍵:
getUiDevice().pressHome();
UiSelector
表示一個在當前顯示界面查詢、獲取特定組件的搜素條件。若是找到多個匹配組件,那麼就返回佈局層次中的第一個匹配組件,返回的是一個 UIObject 對象。構造一個 UiSelector 對象時,能夠組合多個屬性使搜索更精確。若是一個也沒找到,就會拋出一個 UiAutomatorObjectNotFoundException 異常。也能夠用 childSelector() 函數來嵌套多個 UiSelector 實例。例如,下面的示例代碼就展現瞭如何設定一個搜索條件,在當前顯示界面中找到第一個 ListView,而後在這個 ListView 中搜索一個 text 屬性爲 「Apps」的 UI 組件。
UiObject appItem = new UiObject(new UiSelector() .className("android.widget.ListView").instance(1) .childSelector(new UiSelector().text("Apps")));
UiObject
表明一個 UI 組件。建立 一個 UiObject 實例時經過一個 UiSelector 對象來搜索對應的 UI 組件。
下面的示例代碼展現瞭如何建立 UiObject 對象,這兩個對象表示應用程序中的一個 Cancel 按鈕和一個 OK 按鈕。
UiObject cancelButton = new UiObject(new UiSelector().text("Cancel")); UiObject okButton = new UiObject(new UiSelector().text("OK"));
若是須要,你能夠在測試程序的其它地方重用已經建立的 UiObject 實例。要注意的是,在測試代碼中你每次用一個 UiObject 實例對一個 UI 組件進行點擊操做或者查詢其屬性,uiautomator 測試框架都會在當前顯示界面進行一次搜索。
在下面的示例代碼中,uiautomator 測試框架會先搜索 text 屬性爲 「OK」的 UI 組件,若是存在而且是 enable 的,那麼測試框架就會模擬用戶對該組件進行點擊操做。
if(okButton.exists() && okButton.isEnabled()) { okButton.click(); }
也能夠限制搜索條件只搜索特定類的組件。例如,搜索 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,UiSelector 用於搜索多個子控件的容器(例如:一個包含子控件的 Layout)。例如,下面的代碼片斷展現瞭如何建立一個表明一個視頻專輯的 UiCollection,該專輯顯示在一個 FrameLayout 中:
UiCollection videos = new UiCollection(new UiSelector() .className("android.widget.FrameLayout"));
若是這些視頻都顯示在一個 LinearLayout 中,你又想獲取這些視頻的個數:
int count = videos.getChildCount(new UiSelector() .className("android.widget.LinearLayout"));
若是你要從中找出一個 text 屬性爲 「Cute Baby Laughting」的視頻,並模擬用戶去點擊它:
UiObject video = videos.getChildByText(new UiSelector() .className("android.widget.LinearLayout"), "Cute Baby Laughing"); video.click();
對於這個 UI 對象上你一樣能夠模擬其它的用戶操做。例如,你能夠模擬選擇一個與某一視頻線關聯的 checkbox:
UiObject checkBox = video.getChild(new UiSelector() .className("android.widget.Checkbox")); if(!checkBox.isSelected()) checkbox.click();
UiScollable
表明一個可滾動的 UI 組件集合。你能夠用 UiScrollable 來模擬 UI 組件的垂直或者水平滾動。當一個 UI 組件顯示在屏幕之外,你須要滾動才能看到它,這時候這個技術就頗有用。
例以下面的示例代碼演示如何模擬向下滾動設置菜單並點擊一個 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。
A sample uiautomator test case
下面的示例代碼是一個簡單的 test case,它模擬用戶在一個通用 Android 設備上進行設置應用程序的操做。該 test case 模擬用戶執行這個任務一般會作的全部操做,包括打開 Home Screen,打開 All Apps Screen,滾動找到 Settings app 的圖標,而後點擊這個圖標進入設置界面。
package com.uia.example.my; // Import the uiautomator libraries
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 { public void testDemo() throws UiObjectNotFoundException { // 模擬點擊 HOME 按鈕.
getUiDevice().pressHome(); // 如今在 Home Sceen. 接下來咱們模擬用戶進入 All Apps 屏 // 若是用 uiautomatorviewer 工具對 Home Screen 進行截圖分析// 就會發現 All Apps 按鈕的 content-description 屬性的值是 「Apps」 // 咱們能夠用這個屬性值建立一個 UiSelector 來找到這個按鈕。
UiObject allAppsButton = new UiObject(new UiSelector() .description("Apps")); // 模擬進入 All Apps 屏
allAppsButton.clickAndWaitForNewWindow(); // 設置按鈕在 All Apps 屏的 「Apps tab」 中。咱們建立一個 UiSelector 找到 // text 屬性是 「Apps」 的 tab ,而後模擬用戶點擊進入 Apps tab。
UiObject appsTab = new UiObject(new UiSelector() .text("Apps")); // 模擬點擊進入 Apps tab
appsTab.click(); // 接下來在 Apps tab 中模擬用戶滑動屏幕找到設置程序的圖標。 // 由於這個 Apps tab 是能夠滑動的,因此咱們能夠用一個 UiScrollable 對象。
UiScrollable appViews = new UiScrollable(new UiSelector() .scrollable(true)); // 設置爲水平滑動模式(模式是垂直滑動)
appViews.setAsHorizontalList(); // 建立一個 UiSelector 找到設置按鈕, // 而後模擬用戶點擊加載這個程序
UiObject settingsApp = appViews.getChildByText(new UiSelector() .className(android.widget.TextView.class.getName()), "Settings"); settingsApp.clickAndWaitForNewWindow(); // 驗證它的 package name 是否符合預期。
UiObject settingsValidation = new UiObject(new UiSelector() .packageName("com.android.settings")); assertTrue("Unable to detect Settings", settingsValidation.exists()); } }
Building and Deploying Your uiautomator Tests
完成測試代碼以後,根據下面步驟來 build 並把 JAR 文件部署到測試機上:
<android-sdk>/tools/android create uitest-project -n <name> -t 1 -p <path>
<name> 是包含 uiautomator 測試源代碼的工程名字,<path> 是項目文件夾的路徑。
Windows:
set ANDROID_HOME=<path_to_your_sdk>
UNIX:
export ANDROID_HOME=<path_to_your_sdk>
ant build
下面是一個例子adb push <path_to_output_jar> /data/local/tmp/
adb push ~/dev/workspace/LaunchSettings/bin/LaunchSettings.jar /data/local/tmp/
Running uiautomator Tests
下面的例子是展現如何運行 LaunchSettings.jar 測試代碼。該測試位於 com.uia.example.my 包中:
adb shell uiautomator runtest LaunchSettings.jar -c com.uia.example.my.LaunchSettings
關於 uiautomator 的語法、命令、設置的詳細信息請參考 uiautomator。
Best Practices
下面是一些用 uiautomator 框架進行 UI 功能測試的最佳實踐: