使用建構管理裝置調整測試

建構作業管理的裝置可提升自動檢測設備測試的一致性、效能和穩定性。這項功能適用於 API 級別 27 及以上級別,可讓您在專案的 Gradle 檔案中設定虛擬裝置,或遠端的實體測試裝置。Android Gradle 外掛程式在執行自動化測試時,會使用這些設定對這些裝置進行完全管理,即建立、部署及拆卸這些裝置。

這項功能不僅可讓 Android Gradle 外掛程式查看正在執行的測試,也能查看裝置的生命週期,進而以下列方式改善測試體驗的品質:

  • 處理裝置相關問題,確保測試能執行
  • 如果是虛擬裝置,請使用模擬器快照減少裝置啟動時間和記憶體用量,並在測試之間將裝置還原至清空狀態
  • 快取測試結果,並且僅重新執行可能提供不同結果的測試
  • 為本機和遠端測試提供一致的測試環境

建立由建構作業管理的虛擬裝置

您可以在模組層級建構檔案中指定虛擬裝置,用於測試應用程式。以下程式碼範例會建立搭載 API 級別 30 的 Pixel 2,做為建構管理裝置。

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 級別和板型規格) 調整測試,您可以定義多個建構管理裝置,並將其新增至已命名群組。然後,Android Gradle 外掛程式可以同時為群組中的所有裝置執行測試。

以下範例顯示兩個新增至 phoneAndTablet 裝置群組的裝置。

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)
      }
    }
  }
}

執行測試

如要使用您設定的建構管理裝置執行測試,請使用下列指令。device-name 是您在 Gradle 建構指令碼 (例如 pixel2api30) 中設定的裝置名稱,而 BuildVariant 是要測試的應用程式建構變化版本,例如 Debug

Linux 和 macOS

./gradlew device-nameBuildVariantAndroidTest

Windows

gradlew device-nameBuildVariantAndroidTest

如要在受建構管理裝置的群組上執行測試,請使用下列指令。

Linux 和 macOS

./gradlew group-nameGroupBuildVariantAndroidTest
./gradlew group-nameGroupBuildVariantAndroidTest

Windows

gradlew group-nameGroupBuildVariantAndroidTest

測試輸出內容會包含測試報告的 HTML 檔案路徑。您也可以在 IDE 中依序點選「Run」>「Test History」,將測試結果匯入 Android Studio 以便深入分析。

啟用測試資料分割

建構管理裝置支援測試資料分割,可讓您將測試套件分割至多個相同的虛擬裝置執行個體,這些稱為「資料分割」的執行個體會平行執行。使用測試資料分割有助於縮短整體測試執行時間,但會增加額外運算資源。

如要設定用於特定測試執行作業的資料分割數量,請在 gradle.properties 檔案中設定以下內容:

android.experimental.androidTest.numManagedDeviceShards=<number_of_shards>

使用這個選項執行測試時,建構作業管理的裝置會根據您在測試執行作業中為每個裝置設定檔指定的數量佈建資料分割。舉例來說,如果您將測試內容部署至三個裝置群組,並將 numManagedDeviceShards 設為兩個裝置,建構管理裝置就會佈建共計六個虛擬裝置來測試。

測試完成後,Gradle 會在 .proto 檔案中輸出測試結果,以用於測試執行作業中使用的每個資料分割。

使用自動化的測試裝置

建構管理裝置支援一種新型的模擬器裝置,稱為「自動化測試裝置」(ATD),經過最佳化處理後,此裝置可在執行檢測設備測試時,減少耗用的 CPU 和記憶體資源。ATD 可透過下列幾種方式改善執行階段效能:

  • 移除預先安裝的應用程式,這類應用程式通常不適合用來測試
  • 停用通常不適合用來測試應用程式的特定背景服務
  • 停用硬體轉譯功能

開始之前,請務必將 Android Emulator 更新至最新的可用版本。接著,在模組層級建構檔案中定義建構管理裝置時,指定「-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"
        }
      }
    }
  }
}

您也可以建立裝置群組,就像使用其他建構管理裝置一樣。如要進一步發揮效能的改進項目,您也可以使用 ATD 搭配測試資料分割,以縮短測試套件的總測試執行時間。

已從 ATD 映像檔中移除哪些內容?

除了在無頭模式下運作之外,ATD 也會透過移除/停用通常不適合用於測試應用程式程式碼的應用程式和服務,將效能最佳化。下表概略說明我們在 ATD 映像檔中移除或停用的元件,以及這些元件可能不實用的原因。

ATD 映像檔已移除的內容 執行自動化測試時,您為何不需要使用這項功能
Google 產品應用程式:
  • 郵件
  • 地圖介面集
  • Chrome
  • 訊息
  • Play 商店和其他項目
您的自動化測試應著重在自家應用程式的邏輯,並假設其他應用程式或平台可正常運作。

透過 Espresso-Intent,您可以比對並驗證傳出意圖,甚至提供虛設常式回應,以取代實際意圖回應。

設定應用程式和服務:
  • CarrierConfig
  • EmergencyInfo
  • OneTimeInitializer
  • PhotoTable (螢幕保護程式)
  • 佈建
  • 「設定」應用程式
  • StorageManager
  • Telephony APN 設定
  • WallpaperCropper
  • WallpaperPicker
這類應用程式會顯示 GUI,讓使用者變更平台設定、設定裝置或管理裝置儲存空間。這通常不在應用程式等級自動化測試的範圍內。


注意:ATD 映像檔仍會提供設定提供者

SystemUI 您的自動化測試應著重在自家應用程式的邏輯,並假設其他應用程式或平台可正常運作。
AOSP 應用程式和服務:
  • Browser2
  • Calendar
  • Camera2
  • Contacts
  • 撥號
  • DeskClock
  • Gallery2
  • LatinIME
  • Launcher3QuickStep
  • 音樂
  • QuickSearchBox
  • SettingsIntelligence
這些應用程式和服務通常不在應用程式程式碼的自動測試範圍內。

使用 Firebase Test Lab 裝置

使用建構管理裝置時,您可以在 Firebase Test Lab 裝置上大規模執行自動化檢測設備測試。Test Lab 可讓您在各種 Android 實體和虛擬裝置上同時執行測試。這些測試會在遠端 Google 資料中心內執行。有了建構管理裝置支援,建構系統就能根據您的設定,全面管理針對這些 Test Lab 裝置的測試執行作業。

開始使用

下列步驟說明如何搭配使用 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 Developers Console API 程式庫頁面中,啟用 Cloud Testing APICloud Tool Results API。方法是在控制台頂端的搜尋框中輸入 API 名稱,然後在各個 API 的「總覽」頁面上,按一下「啟用 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 的 Pixel 3 裝置,做為建構作業管理的 Test Lab 裝置 ftlDevice。將 com.google.firebase.testlab 外掛程式套用至模組時,即可使用 firebaseTestLab {} 模塊。

Kotlin

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

Groovy

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

如要定義一組建構作業管理的裝置 (包括 Firebase Test Lab 裝置),請參閱「定義裝置群組」。

如要執行測試,請使用執行其他建構管理裝置所用的相同指令。請注意,Gradle 不會同時執行測試,也無法支援 Test Lab 裝置的其他 Google Cloud CLI 設定。

使用智慧型資料分割功能,為測試執行程序進行最佳化調整

如果要在建構管理型 Test Lab 裝置上執行測試,可使用智慧型資料分割功能。此功能會自動對各個資料分割發布測試,讓每個資料分割以大致相同的時間執行,進而減少手動配置作業,並縮短整體測試執行時間。智慧型資料分割會使用您的測試記錄 (或先前測試的執行時間長度資訊),以最適合的方式發布測試。請注意,您需要安裝適用於 Firebase Test Lab 的 0.0.1-alpha05 版 Gradle 外掛程式,才能使用智慧型資料分割。

如要啟用智慧型資料分割,請指定每個資料分割中測試所需的時間。您應將目標資料分割的時間長度設為至少比 timeoutMinutes 少五分鐘,以免在測試完成前資料分割作業遭到取消。

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.
       */
      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
  }
}