アプリケーションのターゲティング例

このカテゴリのインストゥルメンテーション テストは、通常の Android アプリをターゲットとするテストとそれほど変わりません。留意点としては、インストゥルメンテーションを含むテスト アプリケーションは、ターゲットとするアプリケーションと同じ証明書で署名する必要があります。

このガイドは、プラットフォームのソースツリーのワークフローに関する知識があることを前提としています。そうでない場合は、https://source.android.com/source/requirements をご覧ください。ここでは、独自のテスト アプリケーション パッケージをターゲット パッケージに設定して新しいインストゥルメンテーション テストを作成する方法を説明します。コンセプトになじみがない場合は、プラットフォーム テストの概要をご覧ください。

このガイドでは、次のテストをサンプルとして使用します。

  • frameworks/base/packages/Shell/tests

先に進む前に、まずコードを確認して、おおよそのイメージをつかむことをおすすめします。

ソースの場所を決定する

インストゥルメンテーション テストはアプリケーションを対象としているため、テスト ソースコードはプラットフォーム ソースツリーのコンポーネント ソース ディレクトリのルートの下にある tests ディレクトリに配置するのが慣例となっています。

自己インストゥルメント テストのエンドツーエンド サンプルのソースの場所についての説明をご覧ください。

マニフェスト ファイル

通常のアプリケーションと同様に、各インストゥルメンテーション テスト モジュールにはマニフェスト ファイルが必要です。ファイル名を AndroidManifest.xml にしてテスト モジュール用の Android.mk と同じ場所に置くと、BUILD_PACKAGE コアの makefile によって自動的に取り入れられます。

先に進む前に、まずアプリ マニフェストの概要の確認をおすすめします。

マニフェスト ファイルの基本コンポーネントとその機能の概要がわかります。

サンプルの gerrit 変更のマニフェスト ファイルの最新バージョンは、次の URL からアクセスできます。https://android.googlesource.com/platform/frameworks/base/+/master/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 アプリケーション フレームワークがアプリケーション(ここではテスト アプリケーション)を識別するために使用する一意の識別子です。システム内の各ユーザーは、このパッケージ名のアプリケーションを 1 つのみインストールできます。

これは、テスト対象のアプリケーション パッケージとは独立したテスト アプリケーション パッケージであるため、別のパッケージ名を使用する必要があります。接尾辞 .test を追加するのが一般的な慣例です。

さらに、この package 属性は ComponentName#getPackageName() が返すものと同一であり、adb shell 内のさまざまな pm サブコマンドで使用するパッケージとも同一です。

また、パッケージ名は通常 Java パッケージ名と同じスタイルですが、実際にはほとんど関係ありませんので、ご注意ください。つまり、アプリケーション(またはテスト)のパッケージには任意のパッケージ名のクラスを含めることができますが、単純にアプリケーションやテストの最上位 Java パッケージ名をアプリケーション パッケージ名と同一にすることもできます。

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

これは、すべてのインストゥルメンテーション テストに必要です。なぜなら、関連するクラスが別のフレームワーク JAR ライブラリ ファイルにパッケージ化されていることにより、テスト パッケージがアプリケーション フレームワークで呼び出される際に追加のクラスパス エントリが必要になるためです。

android:targetPackage="com.android.shell"
    

上記により、インストゥルメンテーションのターゲット パッケージが com.android.shell.tests に設定されます。インストゥルメンテーションが am instrument コマンドで呼び出されると、フレームワークは com.android.shell.tests プロセスを再起動し、インストゥルメンテーション コードをテスト実行プロセスに挿入します。つまり、テストコードは、テスト対象のアプリケーションで実行されているすべてのクラス インスタンスにアクセスでき、公開されているテストフックに応じて状態を操作できる可能性があります。

シンプルな構成ファイル

新しいテスト モジュールごとに、モジュール メタデータ、コンパイル時の依存関係、パッケージ化手順をビルドシステムに指示するための構成ファイルが必要です。ほとんどの場合、Soong ベースのブループリント ファイル オプションで十分です。詳しくは、シンプルなテスト構成をご覧ください。

複雑な構成ファイル

より複雑なテストの場合、Android のテストハーネスである Trade Federation のテスト構成ファイルも作成する必要があります。

テスト構成では、特別なデバイス セットアップ オプションとデフォルト引数を指定して、テストクラスを提供できます。

サンプルにおける gerrit 変更の構成ファイルの最新バージョンは、次の URL からアクセスできます。https://android.googlesource.com/platform/frameworks/base/+/master/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>
    

これは、指定した target_preparer を使用して、ShellTests.apk をターゲット デバイスにインストールするように Trade Federation に指示します。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.javast.java からアクセスできます。

通常、テストパターンはコンポーネント チームに固有のものですが、一般的に有用な使用パターンがあります。

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

JUnit4 の主な違いは、テストを共通の基本テストクラスから継承する必要がなくなったことです。代わりにプレーンな Java クラスでテストを作成し、アノテーションを使用してテストのセットアップと制約を指定します。この例では、このクラスを Android JUnit4 テストとして実行するように指示しています。

@SmallTest アノテーションは、テストクラス全体のテストサイズを指定しています。このテストクラスに追加されたすべてのテストメソッドは、テストサイズのアノテーションを継承します。テスト前クラスのセットアップ、テスト後のティアダウン、テスト後クラスのティアダウン: JUnit4 の setUp および tearDown メソッドに似ています。 Test アノテーションは、実際のテストにアノテーションを付加するために使用されます。

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

@Before アノテーションは、JUnit4 によってメソッドで使用され、テスト前のセットアップを行います。この例には使用されていませんが、テスト後のティアダウンに使用される @After もあります。同様に、@BeforeClass@AfterClass のアノテーションは JUnit4 によりメソッドで使用され、テストクラス内のすべてのテストを実行する前にセットアップを行い、後でティアダウンできます。クラススコープのセットアップ メソッドとティアダウン メソッドは静的である必要があります。

テストメソッドでは、以前の JUnit とは異なり、メソッド名を test で開始する必要はありませんが、代わりに各メソッドに @Test をアノテーションとして追加する必要があります。通常、テストメソッドはパブリックであり、戻り値を宣言せず、パラメータを受け取らず、例外をスローする場合があります。

        Context context = InstrumentationRegistry.getTargetContext();
    

JUnit4 テストでは、共通の基本クラスが不要になったため、getContext()getTargetContext() で基本クラスメソッドを使用して Context インスタンスを取得する必要がなくなりました。代わりに、新しいテストランナーは InstrumentationRegistry でこれらを管理します。ここには、インストゥルメンテーション フレームワークで作成されたコンテキストや環境のセットアップが保存されます。このクラスを使用して、以下を呼び出すこともできます。

  • getInstrumentation(): Instrumentation クラスに対するインスタンス。
  • getArguments(): -e <key> <value> によって am instrument に渡されるコマンドライン引数

ローカルでのビルドとテスト

最も一般的な使用例の場合、Atest を使用します。

より複雑なカスタマイズが必要な場合は、インストゥルメンテーションの手順に従います。