インストゥルメント化単体テストを作成する

インストゥルメント化単体テストとは、物理デバイスやエミュレータで実行する単体テストのことです。このテストでは、Android フレームワーク API や、AndroidX Test などのサポート API を利用できます。ローカル単体テストに比べて再現性が高い反面、はるかに時間がかかります。したがって、インストゥルメント化単体テストは、実際のデバイスの動作をテストする必要がある場合にのみ使用することをおすすめします。 AndroidX Test には、必要に応じてインストゥルメント化単体テストを簡単に作成できるようにするためのライブラリがいくつか用意されています。たとえば、Android Builder クラスを使用すると、他の方法では作成が困難な Android データ オブジェクトを比較的容易に作成できます。

注: テストの実行に独自の依存関係が必要な場合は、独自に模擬バージョンを用意するか、Mockito などのモック フレームワークを使用して依存関係のモックを用意します。

テスト環境をセットアップする

Android Studio プロジェクトでは、インストゥルメント化テストのソースファイルを module-name/src/androidTest/java/ に保存する必要があります。このディレクトリは、新しいプロジェクトの作成時から存在し、そこにはサンプルのインストゥルメント化テストが含まれています。

最初に、AndroidX Test API を追加します。これにより、対象アプリのインストゥルメント化テストのコードを迅速に作成して実行できるようになります。AndroidX Test には、JUnit 4 テストランナー(AndroidJUnitRunner)と UI 機能テスト用の API(Espresso および UI Automator)が含まれています。

AndroidX Test のテストランナーとルール API を使用するには、さらにプロジェクト用の Android テスト依存関係を構成する必要があります。テストをシンプルに開発するため、Hamcrest ライブラリも含めておきます。これにより、Hamcrest マッチャー API を使用してより柔軟なアサーションを作成できるようになります。

アプリの最上位の build.gradle ファイルの中で、依存関係として次のライブラリを指定する必要があります。

    dependencies {
        androidTestImplementation 'androidx.test:runner:1.1.0'
        androidTestImplementation 'androidx.test:rules:1.1.0'
        // Optional -- Hamcrest library
        androidTestImplementation 'org.hamcrest:hamcrest-library:1.3'
        // Optional -- UI testing with Espresso
        androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
        // Optional -- UI testing with UI Automator
        androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
    }
    

JUnit 4 テストクラスを使用するには、プロジェクトのデフォルトのテスト インストゥルメンテーション ランナーとして AndroidJUnitRunner を指定してください。そのためには、アプリのモジュールレベルの build.gradle ファイルに次の設定を含めます。

    android {
        defaultConfig {
            testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        }
    }
    

インストゥルメント化単体テストクラスを作成する

インストゥルメント化単体テストクラスは、ローカル単体テストクラスの作成方法のセクションで説明したクラスと同様の JUnit 4 テストクラスである必要があります。

インストゥルメント化 JUnit 4 テストクラスを作成するには、デフォルトのテストランナーとして AndroidJUnit4 を指定します。

注: テストスイートで JUnit3 ライブラリと JUnit4 ライブラリの両方が必要な場合は、テストクラス定義の先頭に @RunWith(AndroidJUnit4::class) アノテーションを追加します。

次の例は、Parcelable インターフェースが LogHistory クラスに対して正しく実装されているかどうかを確認するためのインストゥルメント化単体テストの作成方法を示しています。

Kotlin

    import android.os.Parcel
    import android.text.TextUtils.writeToParcel
    import androidx.test.filters.SmallTest
    import androidx.test.runner.AndroidJUnit4
    import com.google.common.truth.Truth.assertThat
    import org.junit.Before
    import org.junit.Test
    import org.junit.runner.RunWith

    const val TEST_STRING = "This is a string"
    const val TEST_LONG = 12345678L

    // @RunWith is required only if you use a mix of JUnit3 and JUnit4.
    @RunWith(AndroidJUnit4::class)
    @SmallTest
    class LogHistoryAndroidUnitTest {
        private lateinit var logHistory: LogHistory

        @Before
        fun createLogHistory() {
            logHistory = LogHistory()
        }

        @Test
        fun logHistory_ParcelableWriteRead() {
            val parcel = Parcel.obtain()
            logHistory.apply {
                // Set up the Parcelable object to send and receive.
                addEntry(TEST_STRING, TEST_LONG)

                // Write the data.
                writeToParcel(parcel, describeContents())
            }

            // After you're done with writing, you need to reset the parcel for reading.
            parcel.setDataPosition(0)

            // Read the data.
            val createdFromParcel: LogHistory = LogHistory.CREATOR.createFromParcel(parcel)
            createdFromParcel.getData().also { createdFromParcelData: List<Pair<String, Long>> ->

                // Verify that the received data is correct.
                assertThat(createdFromParcelData.size).isEqualTo(1)
                assertThat(createdFromParcelData[0].first).isEqualTo(TEST_STRING)
                assertThat(createdFromParcelData[0].second).isEqualTo(TEST_LONG)
            }
        }
    }

    

Java

    import android.os.Parcel;
    import android.util.Pair;
    import androidx.test.filters.SmallTest;
    import androidx.test.runner.AndroidJUnit4;
    import com.google.common.truth.Truth.assertThat;
    import java.util.List;
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;

    // @RunWith is required only if you use a mix of JUnit3 and JUnit4.
    @RunWith(AndroidJUnit4.class)
    @SmallTest
    public class LogHistoryAndroidUnitTest {

        public static final String TEST_STRING = "This is a string";
        public static final long TEST_LONG = 12345678L;
        private LogHistory mLogHistory;

        @Before
        public void createLogHistory() {
            mLogHistory = new LogHistory();
        }

        @Test
        public void logHistory_ParcelableWriteRead() {
            // Set up the Parcelable object to send and receive.
            mLogHistory.addEntry(TEST_STRING, TEST_LONG);

            // Write the data.
            Parcel parcel = Parcel.obtain();
            mLogHistory.writeToParcel(parcel, mLogHistory.describeContents());

            // After you're done with writing, you need to reset the parcel for reading.
            parcel.setDataPosition(0);

            // Read the data.
            LogHistory createdFromParcel = LogHistory.CREATOR.createFromParcel(parcel);
            List<Pair<String, Long>> createdFromParcelData
                    = createdFromParcel.getData();

            // Verify that the received data is correct.
            assertThat(createdFromParcelData.size()).isEqualTo(1);
            assertThat(createdFromParcelData.get(0).first).isEqualTo(TEST_STRING);
            assertThat(createdFromParcelData.get(0).second).isEqaulTo(TEST_LONG);
        }
    }
    

テストスイートを作成する

インストゥルメント化単体テストの実行を整理するために、テストクラスのコレクションをテストスイート クラスにグループ化して、テストをグループごとにまとめて実行できます。テストスイートはネストが可能で、他のテストスイートとグループ化すれば、そのグループに含まれるコンポーネント テストクラスをまとめて実行できます。

テストスイートは、メインのアプリ パッケージと同様のテスト パッケージに含まれています。慣例として、テストスイートのパッケージ名の最後は通常 .suite サフィックスとします(たとえば、com.example.android.testing.mysample.suite)。

単体テスト用のテストスイートを作成するには、JUnit の RunWith クラスと Suite クラスをインポートします。テストスイートに、@RunWith(Suite.class) アノテーションと @Suite.SuitClasses() アノテーションを追加します。@Suite.SuiteClasses() アノテーションに、個々のテストクラスまたはテストスイートを引数としてリストします。

次の例は、UnitTestSuite というテストスイートの実装方法を示しています。このテストスイートでは、テストクラス CalculatorInstrumentationTestCalculatorAddParameterizedTest をグループ化してまとめて実行します。

Kotlin

    import com.example.android.testing.mysample.CalculatorAddParameterizedTest
    import com.example.android.testing.mysample.CalculatorInstrumentationTest
    import org.junit.runner.RunWith
    import org.junit.runners.Suite

    // Runs all unit tests.
    @RunWith(Suite::class)
    @Suite.SuiteClasses(CalculatorInstrumentationTest::class,
            CalculatorAddParameterizedTest::class)
    class UnitTestSuite
    

Java

    import com.example.android.testing.mysample.CalculatorAddParameterizedTest;
    import com.example.android.testing.mysample.CalculatorInstrumentationTest;
    import org.junit.runner.RunWith;
    import org.junit.runners.Suite;

    // Runs all unit tests.
    @RunWith(Suite.class)
    @Suite.SuiteClasses({CalculatorInstrumentationTest.class,
            CalculatorAddParameterizedTest.class})
    public class UnitTestSuite {}
    

インストゥルメント化単体テストを実行する

インストゥルメント化テストを実行するには、次の手順を行います。

  1. ツールバーの [Sync Project] をクリックして、プロジェクトを Gradle と同期します(必須)。
  2. 次のいずれかの方法でテストを実行します。
    • 単一のテストを実行するには、[Project] ウィンドウを開き、対象のテストを右クリックして [Run] をクリックします。
    • クラス内のすべてのメソッドをテストするには、テストファイル内の対象のクラスまたはメソッドを右クリックして [Run] をクリックします。
    • ディレクトリ内のすべてのテストを実行するには、対象のディレクトリを右クリックして [Run tests] をクリックします。

これで、Android Plugin for Gradle により、デフォルト ディレクトリ(src/androidTest/java/)にあるインストゥルメント化テストのコードがコンパイルされ、テスト APK と製品版 APK がビルドされます。続いて、接続されたデバイスまたはエミュレータに両方の APK がインストールされ、テストが実行されます。その後、インストゥルメント化テストの実行結果が Android Studio の [Run] ウィンドウに表示されます。

Firebase Test Lab でテストを実行する

Firebase Test Lab を使用すると、多くの一般的な Android デバイスとデバイス構成(言語 / 地域、画面の向き、画面サイズ、プラットフォーム バージョン)で同時にアプリをテストできます。このテストは、リモートの Google データセンターにある物理デバイスと仮想デバイスで実行されます。アプリの Test Lab へのデプロイは、Android Studio またはコマンドラインから直接行えます。テスト結果として提供されるテストログには、アプリの障害すべてに関する詳細情報が含まれています。

Google アカウントと Firebase プロジェクトがない場合は、Firebase Test Lab の使用を開始する前に以下を行う必要があります。

  1. Google アカウントをまだ持っていない場合は、作成します
  2. Firebase コンソールで、[新規プロジェクトを作成] をクリックします。

    Spark プランの 1 日の無料割り当ての範囲内であれば、Test Lab でのアプリのテストは無料です。

テスト マトリックスを構成してテストを実行する

Android Studio には、Firebase Test Lab へのテストのデプロイ方法を構成できる統合ツールが用意されています。Blaze プランの課金方式で Firebase プロジェクトを作成したら、テスト構成を作成してテストを実行できます。

  1. メインメニューから [Run] > [Edit Configurations] をクリックします。
  2. 新規構成の追加アイコン をクリックして [Android Tests] を選択します。
  3. Android Test 構成ダイアログで以下を行います。
    1. テスト名、モジュール タイプ、テストタイプ、テストクラスなど、テストの詳細を入力または選択します。
    2. [Deployment Target Options] の [Target] プルダウン メニューから [Firebase Test Lab Device Matrix] を選択します。
    3. ログインしていない場合は、[Connect to Google Cloud Platform] をクリックして、アカウントに対する Android Studio のアクセスを許可します。
    4. [Cloud Project] の横にある ボタンをクリックして、リストから Firebase プロジェクトを選択します。
  4. 次のようにして、テスト マトリックスの作成と構成を行います。
    1. [Matrix Configuration] プルダウン リストの横にあるダイアログを開くボタン をクリックします。
    2. 新規構成の追加ボタン(+)をクリックします。
    3. [Name] フィールドに、新しい構成の名前を入力します。
    4. アプリをテストするデバイス、Android バージョン、言語 / 地域、画面の向きを選択します。テスト結果の生成にあたっては、ここで選択した項目のすべての組み合わせが Firebase Test Lab によりテストされます。
    5. [OK] をクリックして構成を保存します。
  5. [Run/Debug Configurations] ダイアログで [OK] をクリックして終了します。
  6. [Run] をクリックしてテストを実行します。

図 1. Firebase Test Lab 用テスト構成の作成

テスト結果を分析する

Firebase Test Lab でテストの実行が完了すると、図 2 に示すように、[Run] ウィンドウが開いて結果が表示されます。実行されたテストをすべて表示するには、[Show Passed] のクリックが必要になる場合があります。

図 2. Firebase Test Lab を使用したインストゥルメント化テストの結果の表示

[Run] ウィンドウのテスト実行ログの先頭に表示されたリンクをたどることで、ウェブ上でテストの分析を行うこともできます。

参考資料

ウェブの結果の解釈について詳しくは、Firebase Test Lab for Android の結果の分析をご覧ください。

参考情報

Espresso を使用した Android のテストに関するその他の情報については、次のリソースをご覧ください。

サンプル

コードラボ