定位應用程序示例

此類儀器測試與針對常規 Android 應用程式的儀器測試沒有太大不同。值得注意的是,包含儀器的測試應用程式需要使用與其目標應用程式相同的憑證進行簽署。

請注意,本指南假設您已經了解平台原始碼樹工作流程的一些知識。如果沒有,請參閱要求。這裡介紹的範例是編寫一個新的儀器測試,其目標套件設定在其自己的測試應用程式包中。如果您不熟悉這個概念,請閱讀平台測試簡介

本指南使用以下測試作為範例:

  • 框架/基礎/套件/Shell/測試

建議先瀏覽一下程式碼以獲得大概的印象,然後再繼續。

確定來源位置

由於插樁測試將針對應用程序,因此慣例是將測試原始碼放置在平台原始碼樹中元件來源目錄根目錄下的tests目錄中。

請參閱自檢測測試的端到端範例中有關來源位置的更多討論。

清單文件

就像常規應用程式一樣,每個儀器測試模組都需要一個清單檔案。如果您將該檔案命名為AndroidManifest.xml並將其提供在測試模組的Android.mk旁邊,它將自動包含在BUILD_PACKAGE核心 makefile 中。

在繼續之前,強烈建議先瀏覽一下應用程式清單概述

這概述了清單文件的基本組件及其功能。

範例 gerrit 變更的清單檔案的最新版本可以在下列位置存取:https://android.googlesource.com/platform/frameworks/base/+/main/packages/Shell/tests/AndroidManifest.xml

為了方便起見,此處包含一個快照:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.shell.tests">

    <application>
        <uses-library android:name="android.test.runner" />

        <activity
            android:name="com.android.shell.ActionSendMultipleConsumerActivity"
            android:label="ActionSendMultipleConsumer"
            android:theme="@android:style/Theme.NoDisplay"
            android:noHistory="true"
            android:excludeFromRecents="true">
            <intent-filter>
                <action android:name="android.intent.action.SEND_MULTIPLE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="*/*" />
            </intent-filter>
        </activity>
    </application>

    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
        android:targetPackage="com.android.shell"
        android:label="Tests for Shell" />

</manifest>

關於清單文件的一些精選註解:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.shell.tests">

package屬性是應用程式套件名稱:這是 Android 應用程式框架用來識別應用程式(或在此上下文中:您的測試應用程式)的唯一識別碼。系統中的每個使用者只能安裝一個具有該套件名稱的應用程式。

由於這是一個測試應用程式包,獨立於被測應用程式包,因此必須使用不同的套件名稱:一個常見的約定是添加後綴.test

此外,此package屬性與ComponentName#getPackageName()傳回的屬性相同,也與您透過adb shell與各種pm子命令互動時所使用的屬性相同。

另請注意,雖然套件名稱通常與 Java 套件名稱的風格相同,但實際上與之沒有關係。換句話說,您的應用程式(或測試)套件可能包含具有任何套件名稱的類,但另一方面,您可以選擇簡單性並讓您的應用程式或測試中的頂級Java 套件名稱與應用程式套件名稱相同。

<uses-library android:name="android.test.runner" />

這是所有 Instrumentation 測試所必需的,因為相關類別打包在單獨的框架 jar 庫檔案中,因此當應用程式框架呼叫測試套件時需要額外的類別路徑條目。

android:targetPackage="com.android.shell"

這會將偵測的目標包設定為com.android.shell 。當透過am instrument命令呼叫檢測時,框架會重新啟動com.android.shell進程,並將檢測程式碼注入到該進程中以執行測試。這也意味著測試程式碼將有權存取被測應用程式中運行的所有類別實例,並且可能能夠根據公開的測試掛鉤來操作狀態。

簡單的設定檔

每個新的測試模組都必須有一個配置文件,以使用模組元資料、編譯時依賴項和打包指令來指導建置系統。在大多數情況下,基於 Soong 的藍圖檔案選項就足夠了。有關詳細信息,請參閱簡單測試配置

複雜的設定檔

對於更複雜的測試,您還需要為 Android 的測試工具Trade Federation編寫測試設定檔。

測試配置可以指定特殊的設備設定選項和預設參數來提供測試類別。

可以在下列位置存取範例 gerrit 變更的最新版本設定檔: frameworks/base/packages/Shell/tests/AndroidTest.xml

為了方便起見,此處包含一個快照:

<configuration description="Runs Tests for Shell.">
    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
        <option name="test-file-name" value="ShellTests.apk" />
    </target_preparer>

    <option name="test-suite-tag" value="apct" />
    <option name="test-tag" value="ShellTests" />
    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
        <option name="package" value="com.android.shell.tests" />
        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
    </test>
</configuration>

關於測試設定檔的一些精選註解:

<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
  <option name="test-file-name" value="ShellTests.apk"/>
</target_preparer>

這告訴 Trade Federation 使用指定的 target_preparer 將 ShellTests.apk 安裝到目標裝置上。 Trade Federation 中有許多可供開發人員使用的目標準備器,它們可用於確保在測試執行之前正確設定裝置。

<test class="com.android.tradefed.testtype.AndroidJUnitTest">
  <option name="package" value="com.android.shell.tests"/>
  <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
</test>

這指定了用於執行測試的 Trade Federation 測試類,並傳入要執行的裝置上的套件以及測試執行程式框架(在本例中為 JUnit)。

請在此處查看有關測試模組配置的更多信息

JUnit4 特性

使用android-support-test庫作為測試運行程序可以採用新的 JUnit4 樣式測試類,並且示例 gerrit 更改包含其功能的一些非常基本的使用。

可以在以下位置存取範例 gerrit 變更的最新原始程式碼: frameworks/base/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java

雖然測試模式通常特定於組件團隊,但也有一些普遍有用的使用模式。

@SmallTest
@RunWith(AndroidJUnit4.class)
public final class FeatureFactoryImplTest {

JUnit4 的一個顯著差異是測試不再需要從公共測試基類別繼承;相反,您可以在普通 Java 類別中編寫測試並使用註解來指示某些測試設定和約束。在此範例中,我們指示此類應作為 Android JUnit4 測試運行。

@SmallTest註解指定了整個測試類別的測試大小:新增到該測試類別中的所有測試方法都繼承此測試大小註解。測試前類別設定、測試後拆卸和測試後類別拆卸:類似於 JUnit4 中的setUptearDown方法。 Test註釋用於註釋實際測試。

    @Before
    public void setup() {
    ...
    @Test
    public void testGetProvider_shouldCacheProvider() {
    ...

JUnit4 在方法上使用@Before註解來執行預測試設定。雖然本例中沒有使用,但還有@After用於測試後拆卸。類似地,JUnit4 可以在方法上使用@BeforeClass@AfterClass註釋,以便在執行測試類別中的所有測試之前執行設置,並在之後執行拆卸。請注意,類別範圍的設定和拆卸方法必須是靜態的。

至於測試方法,與早期版本的 JUnit 不同,它們不再需要以test開頭的方法名稱,而是每個方法都必須使用@Test註解。像往常一樣,測試方法必須是公共的,聲明不傳回值,不帶參數,並且可能拋出異常。

        Context context = InstrumentationRegistry.getTargetContext();

由於 JUnit4 測試不再需要公共基類,因此不再需要透過基類方法透過getContext()getTargetContext()來取得Context實例;相反,新的測試運行程序透過InstrumentationRegistry來管理它們,其中儲存了由儀器框架創建的上下文和環境設定。透過這個類,你還可以呼叫:

  • getInstrumentation()Instrumentation類別的實例
  • getArguments() :透過-e <key> <value>傳遞給am instrument命令列參數

本地建置和測試

對於最常見的用例,請使用Atest

對於需要大量客製化的更複雜的情況,請遵循儀器說明