1. 程式人生 > >7、跨多個應用程式的 UI 測試

7、跨多個應用程式的 UI 測試

跨多個應用程式的UI測試

涉及跨多個應用程式互動的使用者介面(UI)測試使您可以驗證您的應用程式在使用者流程跨越其他應用程式或進入系統UI時的行為。這種使用者流程的一個例子就是訊息應用。他可以使使用者輸入文字資訊,然後啟動 Android 聯絡人選擇器,以便使用者可以選擇訊息的接受者,然後將控制權返回到原始的應用中讓使用者去提交這個訊息。

這個課程涵蓋了如何使用 Android 測試支援庫提供的 UI Automator 測試框架編寫這樣的 UI 測試。UI Automator API 可以使您與裝置上的可見元素互動,不管哪個 Activity 處於焦點。你的測試可以使用方便的描述符來查詢 UI 元件,例如元件上顯示的文字或者他的內容描述。 UI Automator 測試可以在 Android 4.3(API 18)或更高的裝置上執行。

UI Automator 測試框架是一個基於 instrumentation 的API 並且與使用 AndroidJUnitRunner 測試器一起使用。

配置 UI Automator

在開始使用 UI Automator 構建您的 UI 測試之前,請確保配置了您的測試程式碼位置和專案依賴。

在你的Android app module 的 build.gradle 檔案中,你必須設定一個 UI Automator 庫的依賴引用:

dependencies {
    ...
    androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.1'
}

要想優化您的 UI Automator 測試,您應該首先檢查您的目標應用的 UI 元件,並且確保他們是可以被訪問的。這些優化技巧將會在接下來的兩節中介紹。

檢查裝置上的 UI

在設計你的測試之前,檢查裝置上可見的 UI 元件。為了確保您的 UI Automator 測試可以訪問這些元件,檢查這些元件是否含有可見的文字標籤,android:contentDescription 值或者兩個都有。

uiautomatorviewer 工具提供了一種便捷的視覺化的介面去檢查佈局結構並檢視裝置前臺的可見的 UI 元件的屬性。這個資訊可以使你使用 UI Automator 建立更加細緻的測試。例如,你可以建立一個匹配特定可見屬性的 UI 選擇器。

想要啟動 uiautomatorviewer 工具:

  1. 在物理裝置上啟動目標應用

  2. 在你的開發機器上連線裝置

  3. 開啟終端並進入到 /tools/ 資料夾。

  4. 使用下面的命令執行該工具:

$ uiautomatorviewer 

要想檢視你的應用的 UI 屬性:

  1. uiautomatorviewer 介面,點選 Device Screenshot 按鈕。

  2. 將滑鼠懸停在左側面板的快照上檢視由 uiautomatorviewer 工具標識的 UI 元件。屬性列在右下方的面板中,佈局結構在右上方的面板中。

  3. 或者,點選 Toggle NAF Nodes 按鈕來檢視 UI Automator 無法訪問的 UI 元件。只有有限的資訊可以用於這些元件。

要想了解更多關於 Android 提供的常見 UI 元件,請看 使用者介面.

確保你的 Activity 是可以被訪問的

UI Automator 測試框架在已經實現了 Android 輔助功能的應用上執行的更好。當你使用 View 型別的 UI 元素或者 SDK 或支援庫的中View 的子類時,你不需要實現輔助功能,因為這些類已經為你完成了。

但是,一些應用使用自定義的 UI 元素提供了更豐富的使用者體驗。這些元素不會提供自動的訪問支援。如果你的應用程式包含不是來自 SDK 或者支援庫中的 View 的子類的例項。請確保通過完成以下步驟將可訪問性功能新增到這些元素:

建立一個 UI Automator 測試類

你的 UI Automator 測試類應該像 JUnit 4 測試類一樣的方式編寫。要想了解更多關於建立 JUnit 4 測試類和使用 JUnit 4 斷言和註釋,請看 建立一個 Instrement 單元測試類

在你的測試類定義的開始新增 @RunWith(AndroidJUnit4.class) 註解。你也需要將 Andriod 測試支援庫提供的 AndroidJUnitRunner 指定為您的預設測試器。這一步在 Run UI Automator Tests on a Device or Emulator 有更詳細的介紹。

在你的 UI Automator 測試類中實現下面的程式設計模型:

  1. 通過呼叫 UiObject 方法來模擬一個特定的使用者互動以在該 UI 元件上執行,例如呼叫 performMultiPointerGesture() 來模擬一個多點觸控手勢,setText() 來編輯文字欄位。你可以根據需要重複呼叫步驟 2 和步驟 3 的 API,以便測試涉及多個 UI 元件或者使用者動作序列的更加複雜的使用者互動。

  2. 在這些使用者互動執行過後,檢查 UI 是否呈現出預期的狀態或者行為。

以下各節將詳細介紹這些步驟。

訪問 UI 元件

UiDevice 物件是訪問和操作裝置狀態的主要的方式。在你的測試中,你可以呼叫 UiDevice 方法去檢查各種屬性的狀態,例如當前的方向或者顯示的大小。你的測試可以使用 UiDevice 物件來執行裝置級別的動作,例如強制裝置進入特定的旋轉狀態,按下 D-pad 硬體按鈕,然後按 Home(主頁)和 Menu(選單)按鈕。

從裝置的主螢幕開始你的測試是一種很好的做法。從主螢幕(或者你在裝置上選擇的一些其他的開始位置),你可以呼叫 UI Automator API 提供的方法來選擇特定的 UI 元素並與其互動。

下面的程式碼片段展示了你的測試應該如何獲得一個 UiDevice 例項並且模擬一個主頁按鈕的點選:

import org.junit.Before;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.Until;
...

@RunWith(AndroidJUnit4.class)
@SdkSuppress(minSdkVersion = 18)
public class ChangeTextBehaviorTest {

    private static final String BASIC_SAMPLE_PACKAGE
            = "com.example.android.testing.uiautomator.BasicSample";
    private static final int LAUNCH_TIMEOUT = 5000;
    private static final String STRING_TO_BE_TYPED = "UiAutomator";
    private UiDevice mDevice;

    @Before
    public void startMainActivityFromHomeScreen() {
        // Initialize UiDevice instance
        mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());

        // Start from the home screen
        mDevice.pressHome();

        // Wait for launcher
        final String launcherPackage = mDevice.getLauncherPackageName();
        assertThat(launcherPackage, notNullValue());
        mDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)),
                LAUNCH_TIMEOUT);

        // Launch the app
        Context context = InstrumentationRegistry.getContext();
        final Intent intent = context.getPackageManager()
                .getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE);
        // Clear out any previous instances
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
        context.startActivity(intent);

        // Wait for the app to appear
        mDevice.wait(Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)),
                LAUNCH_TIMEOUT);
    }
}

在這個例子中, @SdkSuppress(minSdkVersion = 18) 語句有助於確認測試將僅會在 Android 4.3(API 18)或者更高的裝置上執行,正如 UI Automator 框架要求的那樣。

使用 findObject() 方法來檢索一個 UiObject 物件,它代表了一個匹配給定選擇條件的檢視。你可以根據需要重複使用你在你的應用測試的別的部分建立的 UiObject 例項。注意,每當測試使用 UiObject 例項去點選一個 UI 元件或者查詢一個屬性時, UI Automator 測試框架都會在當前顯示中搜索匹配項。

下面的程式碼片段展示了你的測試應該如何構建一個代表應用程式中 “取消” 按鈕和 “確定” 按鈕的 UiObject 例項。

UiObject cancelButton = mDevice.findObject(new UiSelector()
        .text("Cancel"))
        .className("android.widget.Button"));
UiObject okButton = mDevice.findObject(new UiSelector()
        .text("OK"))
        .className("android.widget.Button"));

// Simulate a user-click on the OK button, if found.
if(okButton.exists() && okButton.isEnabled()) {
    okButton.click();
}

指定一個選擇器

如果你想訪問一個應用中指定的 UI 控制元件,請使用 UiSelector 類。這個類代表了對當前顯示 UI 上的指定元素的查詢。

如果找到了多個匹配的元素,那麼佈局結構中的第一個匹配的元素將會作為目標 UiObject 被返回回來。當侯建 UiSelector 時,你可以將多個屬性連線在一起來優惠你的搜尋。如果沒有匹配的 UI 元素被找到,將會丟擲 UiAutomatorObjectNotFoundException 異常。

你可以使用 childSelector() 方法來巢狀多個 UiSelector 物件。例如,下面的程式碼展示了你的測試應該如何查詢當前顯示的 UI 中第一個 ListView ,然後查詢該 ListView 中具有文字屬性 Apps 的 UI 元素。

UiObject appItem = new UiObject(new UiSelector()
        .className("android.widget.ListView")
        .instance(0)
        .childSelector(new UiSelector()
        .text("Apps")));

最好的做法是,當你指定一個選擇器時,你應該使用資源 ID 而不是文字元素或者內容描述。並不是所有的元素都有文字元素,(例如,toolbar 上的圖示)。文字選擇器是脆弱的,如果 UI 發生細微的變化,則有可能導致測試失敗。他們也有可能不能跨越不同的語言,您的文字選擇器可能不匹配翻譯的字串。

在你的選擇器條件中指定物件狀態可能是有用的。例如,當你想選擇所有被選中 (check) 的元素以便你可以取消選擇 (uncheck) 他們,呼叫 checked() 方法並將引數設定為 true

執行操作

一旦你的測試獲取了一個 UiObject 物件,你可以呼叫 UiObject 類中的方法在該物件表示的 UI 元件上執行使用者操作。你可以指定如下操作:

UI Automator 測試框架允許您通過 getContext() 方法獲得一個 Context 物件來發送一個 Intent 或者啟動一個 Activity,而不用通過 shell 命令。

下面的程式碼片段展示了你的測試應該如何使用一個 Intent 來啟動被測試應用。當你僅僅對測試這個計算器應用感興趣而不關心啟動時,這個方法是有效的。

public void setUp() {
    ...

    // Launch a simple calculator app
    Context context = getInstrumentation().getContext();
    Intent intent = context.getPackageManager()
            .getLaunchIntentForPackage(CALC_PACKAGE);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
            // Clear out any previous instances
    context.startActivity(intent);
    mDevice.wait(Until.hasObject(By.pkg(CALC_PACKAGE).depth(0)), TIMEOUT);
}

對集合進行操作

如果你想模擬在一些專案的集合(例如,音樂專輯中的歌曲或者收件箱中的郵件列表)上的使用者互動,請使用 UiCollection 類。要想建立一個 UiCollection 物件,請指定一個 UiSelector ,用來搜尋 UI 容器或者其他子 UI 元素的包裝器,例如包含子 UI 元素的佈局檢視。

下面的程式碼片段展示了你的測試應該如何構造一個 UiCollection 來表示 FrameLayout 中顯示的視訊專輯:

UiCollection videos = new UiCollection(new UiSelector()
        .className("android.widget.FrameLayout"));

// Retrieve the number of videos in this collection:
int count = videos.getChildCount(new UiSelector()
        .className("android.widget.LinearLayout"));

// Find a specific video and simulate a user-click on it
UiObject video = videos.getChildByText(new UiSelector()
        .className("android.widget.LinearLayout"), "Cute Baby Laughing");
video.click();

// Simulate selecting a checkbox that is associated with the video
UiObject checkBox = video.getChild(new UiSelector()
        .className("android.widget.Checkbox"));
if(!checkBox.isSelected()) checkbox.click();

對滾動檢視執行操作

使用 UiScrollable 類來模擬顯示器上的豎直或者橫向的滾動。當一個 UI 元素位於螢幕外並且需要滾動以將他顯示在視圖裡面時,此技術就很有用。

下面的程式碼片段展示了應該如何向下滾動“設定”選單並且單擊“關於平板電腦”選項:

UiScrollable settingsItem = new UiScrollable(new UiSelector()
        .className("android.widget.ListView"));
UiObject about = settingsItem.getChildByText(new UiSelector()
        .className("android.widget.LinearLayout"), "About tablet");
about.click();

驗證結果

InstrumentationTestCase 繼承自 TestCase ,因此你可以使用標準的 JUnit Assert 方法來測試應用中的 UI 元件返回的期盼的結果。

下面的程式碼片段展示了你的測試如何可以定位計算器應用中的一些按鈕,並且按順序點選他們,然後驗證顯示的是否是正確的結果。

private static final String CALC_PACKAGE = "com.myexample.calc";

public void testTwoPlusThreeEqualsFive() {
    // Enter an equation: 2 + 3 = ?
    mDevice.findObject(new UiSelector()
            .packageName(CALC_PACKAGE).resourceId("two")).click();
    mDevice.findObject(new UiSelector()
            .packageName(CALC_PACKAGE).resourceId("plus")).click();
    mDevice.findObject(new UiSelector()
            .packageName(CALC_PACKAGE).resourceId("three")).click();
    mDevice.findObject(new UiSelector()
            .packageName(CALC_PACKAGE).resourceId("equals")).click();

    // Verify the result = 5
    UiObject result = mDevice.findObject(By.res(CALC_PACKAGE, "result"));
    assertEquals("5", result.getText());
}

在裝置或模擬器上執行 UI Automator 測試

你可以從 Android Studio 或者命令列執行 UI Automator 測試。確保將 AndroidJUnitRunner 作為你工程預設的 instrumentation 工具。

要想執行你的 UI Automator 測試,請按照 測試入門 中的描述的執行 instrumented 測試的步驟。