インストルメンテーション テストが開始されると、インストルメンテーション コードが挿入され、実行のために開始された状態で、そのターゲット パッケージが再起動されます。 1 つの例外として、ここでのターゲット パッケージを Android アプリケーション フレームワーク自体、つまりパッケージandroid
にすることはできません。これを行うと、インストルメンテーションを含むシステム機能をサポートする Android フレームワークを再起動する必要があるという逆説的な状況が発生するためです。自体。
つまり、インストルメンテーション テストは、実行のためにシステム サーバーとも呼ばれる Android フレームワークに自身を挿入することはできません。 Android フレームワークをテストするために、テスト コードはパブリック API サーフェスのみ、またはプラットフォーム ソース ツリーで利用可能な Android インターフェイス定義言語AIDLを介して公開されたサーフェスのみを呼び出すことができます。このカテゴリのテストでは、特定のパッケージを対象にすることは意味がありません。したがって、そのようなインストルメンテーションは、 AndroidManifest.xml
の独自の<manifest>
タグで定義されているように、独自のテスト アプリケーション パッケージを対象として宣言するのが通例です。
要件に応じて、このカテゴリのアプリケーション パッケージをテストすることもできます。
- テストに必要なアクティビティをバンドルします。
- ユーザー ID をシステムと共有します。
- プラットフォーム キーで署名されていること。
- パブリック SDK ではなく、フレームワーク ソースに対してコンパイルされます。
このカテゴリの計測テストは、自己計測と呼ばれることがあります。プラットフォーム ソースでの自己インストルメンテーション テストの例を次に示します。
ここで説明する例は、独自のテスト アプリケーション パッケージに設定されたターゲット パッケージを使用して、新しいインストルメンテーション テストを作成することです。このガイドでは、次のテストを例として使用します。
続行する前に、まずコードを参照して大まかな印象をつかむことをお勧めします。
ソースの場所の決定
通常、チームは、コードをチェックインする場所とテストを追加する場所の確立されたパターンを既に持っています。ほとんどのチームは単一の git リポジトリを所有しているか、他のチームと共有していますが、コンポーネントのソース コードを含む専用のサブ ディレクトリを持っています。
コンポーネント ソースのルート ロケーションが<component source root>
であると仮定すると、ほとんどのコンポーネントにはその下にsrc
およびtests
フォルダーがあり、 Android.mk
(または追加の.mk
ファイルに分割) などのいくつかの追加ファイル、マニフェスト ファイルAndroidManifest.xml
、およびテスト構成ファイル「AndroidTest.xml」。
まったく新しいテストを追加するため、おそらくコンポーネントsrc
の隣にtests
ディレクトリを作成し、コンテンツを入力する必要があります。
場合によっては、さまざまなテスト スイートを個々の apk にパッケージ化する必要があるため、チームがtests
の下にさらにディレクトリ構造を持つことがあります。この場合、 tests
の下に新しいサブディレクトリを作成する必要があります。
構造に関係なく、 tests
ディレクトリまたは新しく作成されたサブ ディレクトリに、サンプルの gerrit 変更のinstrumentation
ディレクトリにあるものと同様のファイルを配置することになります。以下のセクションでは、各ファイルの詳細について説明します。
マニフェスト ファイル
通常のアプリケーションと同様に、各インストルメンテーション テスト モジュールにはマニフェスト ファイルが必要です。ファイルにAndroidManifest.xml
という名前を付けて、テスト モジュールのAndroid.mk
の横に指定すると、 BUILD_PACKAGE
コア makefile によって自動的に含まれます。
先に進む前に、まずアプリ マニフェストの概要を確認することを強くお勧めします。
ここでは、マニフェスト ファイルの基本コンポーネントとその機能の概要を示します。 platform_testing/tests/example/instrumentation/AndroidManifest.xmlの例を参照してください。
便宜上、スナップショットがここに含まれています。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.test.example.helloworld" >
<application/>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="android.test.example.helloworld"
android:label="Hello World Test"/>
</manifest>
マニフェスト ファイルに関するコメントをいくつか選択します。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.test.example.helloworld" >
package
属性はアプリケーション パッケージ名です。これは、Android アプリケーション フレームワークがアプリケーション (または、このコンテキストではテスト アプリケーション) を識別するために使用する一意の識別子です。システム内の各ユーザーは、そのパッケージ名で 1 つのアプリケーションのみをインストールできます。
さらに、このpackage
属性はComponentName#getPackageName()
が返すものと同じであり、 adb shell
を介してさまざまなpm
サブコマンドと対話するために使用するものと同じです。
また、パッケージ名は通常、Java パッケージ名と同じスタイルですが、実際にはほとんど関係がないことに注意してください。言い換えると、アプリケーション (またはテスト) パッケージには任意のパッケージ名を持つクラスが含まれる可能性がありますが、単純にすることを選択して、アプリケーションまたはテストにアプリケーション パッケージ名と同じ最上位の Java パッケージ名を含めることもできます。
android:sharedUserId="android.uid.system"
これは、インストール時に、この apk にコア プラットフォームと同じユーザー ID、つまりランタイム ID を付与する必要があることを宣言します。これは、コア プラットフォームと同じ証明書で署名されている apk に依存することに注意してください (上記のセクションのLOCAL_CERTIFICATE
を参照)。ただし、これらは異なる概念です。
- 一部の権限または API は署名で保護されており、同じ署名証明書が必要です
- 一部のアクセス許可または API では、呼び出し元の
system
ユーザー ID が必要です。これには、呼び出し元のパッケージがユーザー ID をsystem
と共有する必要があります (それがコア プラットフォーム自体とは別のパッケージである場合)。
<uses-library android:name="android.test.runner" />
これは、関連するクラスが別のフレームワーク jar ライブラリ ファイルにパッケージ化されているため、すべてのインストルメンテーション テストに必要です。したがって、テスト パッケージがアプリケーション フレームワークによって呼び出されるときに、追加のクラスパス エントリが必要になります。
android:targetPackage="android.test.example.helloworld"
ここでtargetPackage
が、このファイルのmanifest
タグで宣言されているpackage
属性と同じように宣言されていることに気付いたかもしれません。テストの基本で述べたように、このカテゴリのインストルメンテーション テストは通常、フレームワーク API のテストを目的としているため、それ自体以外の特定の対象アプリケーション パッケージを使用することはあまり意味がありません。
シンプルな設定ファイル
新しい各テスト モジュールには、ビルド システムにモジュール メタデータ、コンパイル時の依存関係、およびパッケージ化手順を指示するための構成ファイルが必要です。ほとんどの場合、Soong ベースのブループリント ファイル オプションで十分です。詳細については、単純なテスト構成を参照してください。
複雑な構成ファイル
これらのより複雑なケースでは、Android のテスト ハーネスであるTrade Federation用のテスト構成ファイルも作成する必要があります。
テスト コンフィギュレーションでは、特別なデバイス セットアップ オプションとデフォルト引数を指定して、テスト クラスを提供できます。 /platform_testing/tests/example/instrumentation/AndroidTest.xmlの例を参照してください。
便宜上、スナップショットがここに含まれています。
<configuration description="Runs sample instrumentation test.">
<target_preparer class="com.android.tradefed.targetprep.TestFilePushSetup"/>
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
<option name="test-file-name" value="HelloWorldTests.apk"/>
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"/>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"/>
<option name="test-suite-tag" value="apct"/>
<option name="test-tag" value="SampleInstrumentationTest"/>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="android.test.example.helloworld"/>
<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="HelloWorldTests.apk"/>
</target_preparer>
これは Trade Federation に、指定された target_preparer を使用してターゲット デバイスに HelloWorldTests.apk をインストールするように指示します。 Trade Federation の開発者が利用できるターゲット作成ツールは多数あり、これらを使用して、テスト実行前にデバイスが適切にセットアップされていることを確認できます。
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="android.test.example.helloworld"/>
<option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
</test>
これは、テストの実行に使用する Trade Federation テスト クラスを指定し、実行するデバイス上のパッケージと、この場合は JUnit であるテスト ランナー フレームワークに渡します。
詳細については、「テスト モジュールの構成」を参照してください。
JUnit4 の機能
android-support-test
ライブラリをテスト ランナーとして使用すると、新しい JUnit4 スタイルのテスト クラスを採用できます。サンプルの gerrit 変更には、その機能の非常に基本的な使用方法が含まれています。 /platform_testing/tests/example/instrumentation/src/android/test/example/helloworld/HelloWorldTest.javaの例を参照してください。
通常、テスト パターンはコンポーネント チームに固有のものですが、一般的に役立つ使用パターンがいくつかあります。
@RunWith(JUnit4.class)
public class HelloWorldTest {
JUnit4 の大きな違いは、テストが共通の基本テスト クラスから継承する必要がなくなったことです。代わりに、プレーンな Java クラスでテストを記述し、注釈を使用して特定のテスト設定と制約を示します。この例では、このクラスを JUnit4 テストとして実行するように指示しています。
@BeforeClass
public static void beforeClass() {
...
@AfterClass
public static void afterClass() {
...
@Before
public void before() {
...
@After
public void after() {
...
@Test
@SmallTest
public void testHelloWorld() {
...
@Before
および@After
アノテーションは、JUnit4 によってメソッドで使用され、テスト前のセットアップとテスト後のティアダウンを実行します。同様に、@BeforeClass および@BeforeClass
アノテーションは、 @AfterClass
によってメソッドで使用され、テスト クラス内のすべてのテストを実行する前にセットアップを実行し、その後でティアダウンを実行します。クラス スコープのセットアップ メソッドとティアダウン メソッドは静的でなければならないことに注意してください。テスト メソッドに関しては、以前のバージョンの JUnit とは異なり、メソッド名をtest
で始める必要はなくなりました。代わりに、それぞれに@Test
アノテーションを付ける必要があります。いつものように、テスト メソッドはパブリックである必要があり、戻り値を宣言せず、パラメーターをとらず、例外をスローする場合があります。
重要: テスト メソッド自体には@Test
アノテーションが付けられます。テストをtestHelloWorld
経由で実行するには、テスト サイズで注釈を付ける必要があることに注意して@SmallTest
。アノテーションは、メソッド スコープまたはクラス スコープで適用できます。
instrumentation
へのアクセス
基本的な hello world の例ではカバーされていませんが、Android テストでInstrumentation
インスタンスへのアクセスが必要になることはかなり一般的です。これは、アプリケーション コンテキスト、アクティビティ ライフサイクル関連のテスト API などへのアクセスを提供するコア API インターフェイスです。
JUnit4 テストは共通の基本クラスを必要としなくなったため、 InstrumentationTestCase#getInstrumentation()
を介してInstrumentation
インスタンスを取得する必要がなくなりました。代わりに、新しいテスト ランナーは、インストルメンテーション フレームワークによって作成されたコンテキストおよび環境設定が格納されるInstrumentationRegistry
を介してインスタンスを管理します。
InstrumentationRegistry
クラスのインスタンスにアクセスするには、 Instrumentation
クラスで静的メソッドgetInstrumentation()
を呼び出すだけです。
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()
ローカルでビルドしてテストする
最も一般的な使用例では、 Atestを使用します。
高度なカスタマイズを必要とするより複雑なケースについては、インストルメンテーションの手順に従ってください。