Gradle で管理されているデバイスを使用したテストのスケーリング

Gradle で管理されているデバイスを使用すると、自動インストルメンテーション テストの整合性、パフォーマンス、信頼性が向上します。API レベル 27 以降で利用可能なこの機能では、プロジェクトの Gradle ファイルで仮想またはリモートの物理テストデバイスを設定できます。この構成は、自動テスト実行時にこれらのデバイスを完全に管理(つまり、作成、デプロイ、破棄)するために、ビルドシステムによって使用されます。

この機能を使用すると、Gradle は実行中のテストだけでなく、デバイスのライフサイクルも把握できるため、テスト エクスペリエンスの品質が次のように向上します。

  • テストを確実に実行するために、デバイス関連の問題に対応する
  • 仮想デバイスの場合、エミュレータ スナップショットを使用してデバイスの起動時間とメモリ使用量を改善し、テスト間でデバイスをクリーンな状態に復元します。
  • テスト結果をキャッシュに保存し、異なる結果が得られる可能性のあるテストのみを再実行する
  • 一貫したテスト環境で、ローカルテストとリモートテストを実行する

Gradle で管理されている仮想デバイスを作成する

モジュール レベルのビルドファイルで、Gradle がアプリのテストに使用する仮想デバイスを指定できます。次のコードサンプルは、API レベル 30 を搭載した Google Pixel 2 を Gradle で管理されているデバイスとして作成します。

Kotlin

android {
  testOptions {
    managedDevices {
      localDevices {
        create("pixel2api30") {
          // Use device profiles you typically see in Android Studio.
          device = "Pixel 2"
          // Use only API levels 27 and higher.
          apiLevel = 30
          // To include Google services, use "google".
          systemImageSource = "aosp"
        }
      }
    }
  }
}

Groovy

android {
  testOptions {
    managedDevices {
      localDevices {
        pixel2api30 {
          // Use device profiles you typically see in Android Studio.
          device = "Pixel 2"
          // Use only API levels 27 and higher.
          apiLevel = 30
          // To include Google services, use "google".
          systemImageSource = "aosp"
        }
      }
    }
  }
}

デバイスのグループを定義する

さまざまな API レベルやフォーム ファクタなど、複数のデバイス設定でテストをスケーリングするには、Gradle で管理するデバイスを複数定義し、名前付きグループに追加します。これにより、Gradle はグループ内のすべてのデバイスに対して、テストを同時に実行できます。

次の例は、phoneAndTablet というデバイス グループに追加された 2 つのデバイスを示しています。

Kotlin

testOptions {
  managedDevices {
    localDevices {
      create("pixel2api29") { ... }
      create("nexus9api30") { ... }
    }
    groups {
      create("phoneAndTablet") {
        targetDevices.add(devices["pixel2api29"])
        targetDevices.add(devices["nexus9api30"])
      }
    }
  }
}

Groovy

testOptions {
  managedDevices {
    localDevices {
      pixel2api29 { ... }
      nexus9api30 { ... }
    }
    groups {
      phoneAndTablet {
        targetDevices.add(devices.pixel2api29)
        targetDevices.add(devices.nexus9api30)
      }
    }
  }
}

テストの実施

構成した Gradle で管理されているデバイスを使用してテストを実行するには、次のコマンドを使用します。device-name は、Gradle ビルド スクリプトで構成したデバイス名(pixel2api30 など)で、BuildVariant は、テストするアプリのビルド バリアントです。

Windows の場合:

gradlew device-nameBuildVariantAndroidTest

Linux または macOS の場合:

./gradlew device-nameBuildVariantAndroidTest

Gradle で管理されているデバイスのグループでテストを実行するには、次のコマンドを使用します。

Windows の場合:

gradlew group-nameGroupBuildVariantAndroidTest

Linux または macOS の場合:

./gradlew group-nameGroupBuildVariantAndroidTest

テストの出力には、テストレポートを含む HTML ファイルのパスが含まれます。IDE で [Run] > [Test History] をクリックし、テスト結果を Android Studio にインポートしてさらに分析することもできます。

テストのシャーディングを有効にする

Gradle で管理されるデバイスはテストのシャーディングをサポートしているため、並列して実行される「シャード」という多数の同じ仮想デバイス インスタンスにテストスイートを分割して実行できます。テストのシャーディングを使用すると、追加のコンピューティング リソースを消費することになりますが、全体的なテスト実行時間は短縮できます。

特定のテスト実行中に使用するシャードの数を設定するには、gradle.properties ファイルで次のように設定します。

android.experimental.androidTest.numManagedDeviceShards=<number_of_shards>

このオプションを使用してテストを実行する場合、Gradle で管理されているデバイスは、テストを実行する際、各デバイス プロファイルに指定したシャード数をプロビジョニングします。たとえば、テストを 3 つのデバイスで構成されるデバイス グループにデプロイし、numManagedDeviceShards を 2 つに設定した場合、Gradle で管理されているデバイスは、テストを実行するために合計 6 つの仮想デバイスをプロビジョニングします。

テストが完了すると、テスト実行中に使用されるシャードごとに、Gradle からテスト結果が .proto ファイルに出力されます。

自動テストデバイスを使用する

Gradle で管理されているデバイスは、自動テストデバイス(ATD)と呼ばれるタイプのエミュレータ デバイスに対応しています。これは、インストルメンテーション テストの実行時に CPU リソースとメモリリソースを削減するように最適化されています。ATD は、次のような方法で実行時のパフォーマンスを改善します。

  • 一般的にはアプリのテストに役立たないプリインストールされているアプリを削除する
  • 一般的にはアプリのテストに役立たない特定のバックグラウンド サービスを無効化する
  • ハードウェア レンダリングを無効化する

開始する前に、Android Emulator をアップデートして、利用可能な最新バージョンにしてください。次に、モジュール レベルのビルドファイルで Gradle で管理されているデバイスを定義するときに、以下のように「-atd」イメージを指定します。

Kotlin

android {
  testOptions {
    managedDevices {
      localDevices {
        create("pixel2api30") {
          // Use device profiles you typically see in Android Studio.
          device = "Pixel 2"
          // ATDs currently support only API level 30.
          apiLevel = 30
          // You can also specify "google-atd" if you require Google Play Services.
          systemImageSource = "aosp-atd"
        }
      }
    }
  }
}

Groovy

android {
  testOptions {
    managedDevices {
      localDevices {
        pixel2api30 {
          // Use device profiles you typically see in Android Studio.
          device = "Pixel 2"
          // ATDs currently support only API level 30.
          apiLevel = 30
          // You can also specify "google-atd" if you require Google Play Services.
          systemImageSource = "aosp-atd"
        }
      }
    }
  }
}

Gradle で管理されている他のデバイスと同様に、デバイス グループを作成することもできます。パフォーマンスをさらに向上させるには、テストのシャーディングで ATD を使用して、テストスイートの合計テスト実行時間を短縮することもできます。

ATD イメージから削除されるもの

ATD は、ヘッドレス モードで動作するだけでなく、アプリのコードのテストに通常は不要なアプリとサービスを削除または無効化してパフォーマンスを最適化します。以下の表に、ATD イメージで削除または無効化したコンポーネントの概要と、それらが有用でない理由を示します。

ATD 画像内で削除されるもの 自動テストを実行するときにこれを必要としない理由
Google サービスのアプリ:
  • メール
  • マップ
  • Chrome
  • メッセージ
  • Play ストア、その他
自動テストでは、他のアプリまたはプラットフォームが正しく機能していると仮定して、対象アプリのロジックのテストに専念できます。

Espresso-Intents を使用すれば、送信されるインテントのマッチングや検証を行えるうえ、実際のインテント レスポンスの代わりにスタブ レスポンスを使うこともできます。

アプリとサービスの設定:
  • CarrierConfig
  • EmergencyInfo
  • OneTimeInitializer
  • PhotoTable(スクリーン セーバー)
  • プロビジョニング
  • 設定アプリ
  • StorageManager
  • 電話 APN の構成
  • WallpaperCropper
  • WallpaperPicker
これらのアプリは、エンドユーザーがプラットフォーム設定の変更、デバイスのセットアップ、デバイス ストレージの管理を行うための GUI を提供します。これは通常、アプリレベルの自動テストの対象外です。


注: 設定プロバイダは ATD イメージで引き続き使用できます。

SystemUI 自動テストでは、他のアプリまたはプラットフォームが正しく機能していると仮定して、対象アプリのロジックのテストに専念できます。
AOSP アプリとサービス:
  • Browser2
  • カレンダー
  • Camera2
  • 連絡先
  • 電話アプリ
  • DeskClock
  • Gallery2
  • LatinIME
  • Launcher3QuickStep
  • 音楽
  • QuickSearchBox
  • SettingsIntelligence
これらのアプリとサービスは、通常、アプリのコードの自動テストの対象外です。

Firebase Test Lab デバイスを使用する

Gradle で管理されているデバイスを使用すると、Firebase Test Lab デバイスで自動インストルメンテーション テストを大規模に実行できます。Test Lab を使用すると、物理デバイスと仮想デバイスの両方を含む、さまざまな Android デバイスで同時にテストを実行できます。これらのテストは、リモートの Google データセンターで実行されます。Gradle で管理されているデバイスのサポートにより、ビルドシステムは、これらの Test Lab デバイスに対するテストの実行を、構成に基づいて完全に管理できます。

始める

次の手順では、Gradle で管理されているデバイスで Firebase Test Lab デバイスの使用を開始する方法について説明します。以下の手順では、gcloud CLI を使用してユーザー認証情報を提供しますが、これはすべての開発環境に当てはまるわけではありません。必要に応じて使用する認証プロセスの詳細については、アプリケーションのデフォルト認証情報の仕組みをご覧ください。

  1. Firebase プロジェクトを作成するには、Firebase コンソールに移動します。[プロジェクトを追加] をクリックし、画面の指示に従ってプロジェクトを作成します。プロジェクト ID を覚えておいてください。

  2. Google Cloud CLI をインストールするには、gcloud CLI をインストールする手順に沿って操作します。

  3. ローカル環境を設定します。

    1. gcloud で Firebase プロジェクトにリンクします。

      gcloud config set project FIREBASE_PROJECT_ID
      
    2. API アクセスのためのユーザー認証情報の使用を承認します。モジュール レベルのビルド スクリプトで DSL を使用して、サービス アカウントの JSON ファイルを Gradle に渡して承認することをおすすめします。

      Kotlin

      firebaseTestLab {
        ...
        serviceAccountCredentials.set(file(SERVICE_ACCOUNT_JSON_FILE))
      }
      

      Groovy

      firebaseTestLab {
        ...
        serviceAccountCredentials = file(SERVICE_ACCOUNT_JSON_FILE)
      }
      

      または、次のターミナル コマンドを使用して手動で認証することもできます。

      gcloud auth application-default login
      
    3. 省略可: Firebase プロジェクトを割り当てプロジェクトとして追加します。この手順は、Test Lab の無料割り当てを超過した場合にのみ必要です。

      gcloud auth application-default set-quota-project FIREBASE_PROJECT_ID
      
  4. 必要な API を有効にします。

    Google デベロッパー コンソールの API ライブラリ ページで、コンソール上部の検索ボックスにこれらの API 名を入力し、各 API の概要ページで [Enable API] をクリックして、Cloud Testing API および Cloud Tool Results API を有効にします。

  5. Android プロジェクトを構成します。

    1. 最上位のビルド スクリプトに Firebase Test Lab プラグインを追加します。

      Kotlin

      plugins {
        ...
        id("com.google.firebase.testlab") version "0.0.1-alpha05" apply false
      }
      

      Groovy

      plugins {
        ...
        id 'com.google.firebase.testlab' version '0.0.1-alpha05' apply false
      }
      
    2. gradle.properties ファイルでカスタム デバイスタイプを有効にします。

      android.experimental.testOptions.managedDevices.customDevice=true
      
    3. モジュール レベルのビルド スクリプトに Firebase Test Lab プラグインを追加します。

      Kotlin

      plugins {
       ...
       id "com.google.firebase.testlab"
      }
      

      Groovy

      plugins {
       ...
       id 'com.google.firebase.testlab'
      }
      

Test Lab デバイスを指定する

モジュール レベルのビルド スクリプトでアプリをテストするために使用する Gradle 用 Firebase Test Lab デバイスを指定できます。次のコードサンプルでは、API レベル 30 を実行する Google Pixel 3 を、ftlDevice という Gradle で管理されている Test Lab デバイスとして作成します。firebaseTestLab {} ブロックは、com.google.firebase.testlab プラグインをモジュールに適用するときに使用できます。

Kotlin

firebaseTestLab {
  managedDevices {
    create("ftlDevice") {
      device = "Pixel3"
      apiLevel = 30
    }
  }
  ...
}

Groovy

firebaseTestLab {
  managedDevices {
    ftlDevice {
      device = "Pixel3"
      apiLevel = 30
    }
  }
  ...
}

Gradle で管理されているデバイスのグループ(Firebase Test Lab デバイスを含む)を定義するには、デバイスのグループを定義するをご覧ください。

テストを実行するには、他の Gradle で管理されているデバイスを実行する場合と同じコマンドを使用します。Gradle はテストを並行して実行しません。また、Test Lab デバイス用の他の Google Cloud CLI 構成もサポートしません。

スマート シャーディングでテスト実行を最適化する

Gradle で管理されている Test Lab デバイスでのテストでは、スマート シャーディングがサポートされています。スマート シャーディングは、各シャードがほぼ同時に実行されるようにシャードにテストを自動的に分散します。これにより、手動割り当ての労力と全体的なテスト実行時間が削減されます。スマート シャーディングは、テスト履歴、つまりテストの実行にかかった時間に関する情報を使用して、最適な方法でテストを分散します。スマート シャーディングを使用するには、Firebase Test Lab 用の Gradle プラグインのバージョン 0.0.1-alpha05 が必要です。

スマート シャーディングを有効にするには、各シャード内のテストにかかる時間を指定します。テストが完了する前にシャードがキャンセルされる事態を避けるため、ターゲット シャードの時間は timeoutMinutes より少なくとも 5 分短い値に設定する必要があります。

firebaseTestLab {
  ...
  testOptions {
    targetedShardDurationMinutes = 2
  }
}

詳細については、Firebase Test Lab デバイスの DSL オプションをご覧ください。

Test Lab デバイス用の DSL の更新

テスト実行のカスタマイズや、すでに使用している他のソリューションからの移行に役立つ DSL オプションを構成できます。これらのオプションの一部については、次のコード スニペットをご覧ください。

firebaseTestLab {
  ...

  /**
   * A path to a JSON file that contains service account credentials to access to
   * a Firebase Test Lab project.
   */
  serviceAccountCredentials.set(file("your_service_account_credentials.json"))


  testOptions {
    fixture {
      /**
       * Whether to grant permissions on the device before tests begin.
       * Available options are "all" or "none".
       *
       * Default value is "all".
       */
      grantedPermissions = "all"

      /**
       * Map of files to push to the device before starting the test.
       *
       * The key is the location on the device.
       * The value is the location of the file, either local or in Google Cloud.
       */
      extraDeviceFiles["/sdcard/dir1/file1.txt"] = "local/file.txt"
      extraDeviceFiles["/sdcard/dir2/file2.txt"] = "gs://bucket/file.jpg"

      /**
       * The name of the network traffic profile.
       *
       * Specifies network conditions to emulate when running tests.
       *
       * Default value is empty.
       */
      networkProfile = "LTE"
    }

    execution {
      /**
       * The maximum time to run the test execution before cancellation,
       * measured in minutes. Does not include the setup or teardown of device,
       * and is handled server-side.
       *
       * The maximum possible testing time is 45 minutes on physical devices
       * and 60 minutes on virtual devices.
       *
       * Defaults to 15 minutes.
       */
       timeoutMinutes = 30

      /**
       * Number of times the test should be rerun if tests fail.
       * The number of times a test execution should be retried if one
       * or more of its test cases fail.
       *
       * The max number of times is 10.
       *
       * The default number of times is 0.
       */
      maxTestReruns = 2

      /**
       * Ensures only a single attempt is made for each execution if
       * an infrastructure issue occurs. This doesn't affect `maxTestReruns`.
       * Normally, two or more attempts are made by Firebase Test Lab if a
       * potential infrastructure issue is detected. This is best enabled for
       * latency sensitive workloads. The number of execution failures might be
       * significantly greater with `failFast` enabled.
       *
       * Defaults to false.
       */
      failFast = false

      /**
       * The number of shards to split the tests across.
       *
       * Default to 0 for no sharding.
       */
      numUniformShards = 20
    }

    /**
     * For smart sharding, the target length of time each shard should takes in
     * minutes. Maxes out at 50 shards for physical devices and 100 shards for
     * virtual devices.
     *
     * Only one of numUniformShards or targetedShardDurationMinutes can be set.
     *
     * Defaults to 0 for no smart sharding.
     */
     targetedShardDurationMinutes = 15
    }

    results {
      /**
       * The name of the Google storage bucket to store the test results in.
       *
       * If left unspecified, the default bucket is used.
       *
       * Please refer to Firebase Test Lab permissions for required permissions
       * for using the bucket.
       */
      cloudStorageBucket = "bucketLocationName"

      /**
       * Name of test results for the Firebase console history list.
       * All tests results with the same history name are grouped
       * together in the Firebase console in a time-ordered test history list.
       *
       * Defaults to the application label in the APK manifest in Flank/Fladle.
       */
      resultsHistoryName = "application-history"

      /**
       * List of paths to copy from the test device's storage to the test
       * results folder. These must be absolute paths under /sdcard or
       * /data/local/tmp.
       */
      directoriesToPull.addAll(
        "/sdcard/path/to/something"
      )

      /**
       * Whether to enable video recording during the test.
       *
       * Disabled by default.
       */
      recordVideo = false

      /**
       * Whether to enable performance metrics. If enabled, monitors and records
       * performance metrics such as CPU, memory, and network usage.
       *
       * Defaults to false.
       */
      performanceMetrics = true
  }
}