使用 Gradle 管理的设备扩展测试范围

Gradle 管理的设备可以提高自动化检测测试的一致性、性能和可靠性。此功能适用于 API 级别 27 及更高版本,可让您在项目的 Gradle 文件中配置虚拟或远程物理测试设备。构建系统使用这些配置来完全管理(即创建、部署和拆除)执行自动化测试时使用的设备。

此功能使 Gradle 不仅能够查看您正在运行的测试,还可以查看设备的生命周期,从而通过以下方式提高测试体验的质量

  • 处理与设备相关的问题,以确保执行测试
  • 对于虚拟设备,使用模拟器快照来缩短设备启动时间和内存使用量,并在测试之间将设备恢复到干净状态
  • 缓存测试结果,并且仅重新运行可能产生不同结果的测试
  • 为在本地和远程测试运行之间运行测试提供一致的环境

创建虚拟 Gradle 管理的设备

您可以在模块级构建文件中指定 Gradle 要用于测试应用的虚拟设备。以下代码示例创建了运行 API 级别 30 的 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 的设备组中的设备。

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 中点击运行 > 测试历史记录将测试结果导入 Android Studio 以进行进一步分析。

启用测试分片

Gradle 管理的设备支持测试分片,这使您可以将测试套件拆分到多个相同的虚拟设备实例(称为分片)中,这些实例并行运行。使用测试分片可以帮助缩短整体测试执行时间,但需要额外的计算资源。

要设置在给定测试运行中要使用的分片数,请在 gradle.properties 文件中设置以下内容

android.experimental.androidTest.numManagedDeviceShards=<number_of_shards>

使用此选项运行测试时,Gradle 管理的设备会为测试运行中每个设备配置文件预配您指定的分片数量。例如,如果您将测试部署到包含三个设备的设备组并将 numManagedDeviceShards 设置为 2,则 Gradle 管理的设备将为您的测试运行预配总共六个虚拟设备。

测试完成后,Gradle 会为测试运行中使用的每个分片输出 .proto 文件中的测试结果。

使用自动化测试设备

Gradle 管理的设备支持一种称为自动化测试设备 (ATD) 的模拟器设备,它经过优化,可以在运行检测测试时减少 CPU 和内存资源。ATD 通过以下几种方式提高运行时性能

  • 删除通常对测试您的应用没有用的预安装应用
  • 禁用通常对测试您的应用没有用的某些后台服务
  • 禁用硬件渲染

在开始之前,请确保您将 Android 模拟器更新到最新版本。然后,在模块级构建文件中定义 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(屏幕保护程序)
  • Provision
  • 设置应用
  • 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 设备运行测试。

开始使用

以下步骤介绍了如何开始将 Firebase Test Lab 设备与 Gradle 管理的设备一起使用。请注意,这些步骤使用 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 访问。我们建议通过将服务帐号 JSON 文件传递到 Gradle 来进行授权,方法是使用模块级构建脚本中的DSL

      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,作为名为 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 短五分钟,以避免分片在测试完成前被取消的情况。

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