从命令行测试

本文档介绍了如何直接从命令行运行测试。本文档假设您已经了解如何创建 Android 应用并为应用编写测试。有关如何为应用构建测试的更多信息,请参阅在 Android 上测试应用

当您使用 Gradle 构建系统构建应用时,Android Gradle 插件允许您通过命令行从 Gradle 项目中运行测试。为了实现更精细的控制,您可以选择通过 Android 调试桥 (adb) shell 运行测试。这在持续集成环境中运行测试时非常有用。

要了解如何使用 Gradle 为您管理的虚拟设备从命令行运行自动化的插桩测试,请参阅使用 Gradle 管理的设备扩展您的测试

使用 Gradle 运行测试

Android Gradle 插件允许您通过命令行从 Gradle 项目中运行测试。

下表总结了如何使用 Gradle 运行测试

表 1. 使用 Gradle 运行测试的不同方式

单元测试类型 运行命令 测试结果位置
本地单元测试 运行 test 任务

./gradlew test
HTML 测试结果文件
path_to_your_project/module_name/build/reports/tests/ 目录。

XML 测试结果文件
path_to_your_project/module_name/build/test-results/ 目录。

插桩单元测试 运行 connectedAndroidTest 任务

./gradlew connectedAndroidTest
HTML 测试结果文件
path_to_your_project/module_name/build/reports/androidTests/connected/ 目录。

XML 测试结果文件
path_to_your_project/module_name/build/outputs/androidTest-results/connected/ 目录。

Gradle 支持任务名称缩写。例如,您可以通过输入以下命令来启动 connectedAndroidTest 任务

./gradlew cAT

您还可以选择运行 Gradle 任务 checkconnectedCheck。这些任务分别运行您的本地或插桩测试,但还会包含由其他 Gradle 插件添加的检查项。

在模块上运行测试

testconnectedAndroidTest 任务会在项目中的每个模块上运行测试。您可以通过在 testconnectedAndroidTest 任务前加上模块名称和冒号 (:) 来在特定模块上运行测试。例如,以下命令仅为 mylibrary 模块运行插桩测试

./gradlew mylibrary:connectedAndroidTest

在构建变体上运行测试

testconnectedAndroidTest 任务会在项目中的每个构建变体上运行测试。您可以使用以下语法定位特定的构建变体

  • 对于本地单元测试
    ./gradlew testVariantNameUnitTest
  • 对于插桩测试
    ./gradlew connectedVariantNameAndroidTest

运行特定的测试方法或类

运行本地单元测试时,Gradle 允许您使用 --tests 标记定位特定的测试。例如,以下命令仅为指定的构建变体运行 sampleTestMethod 测试。要了解有关使用 --tests 标记的更多信息,请阅读 Gradle 关于测试过滤的文档。


./gradlew testVariantNameUnitTest --tests '*.sampleTestMethod'

使用 adb 运行测试

当您通过 Android 调试桥 (adb) 从命令行运行测试时,与任何其他方法相比,您有更多的选择来决定运行哪些测试。您可以选择单个测试方法、根据自定义注解过滤测试或指定测试选项。由于测试运行完全由命令行控制,您可以通过 shell 脚本以多种方式自定义测试。

要从命令行运行测试,请运行 adb shell 以在您的设备或模拟器上启动命令行 shell。在该 shell 中,您可以使用 am 命令与活动管理器 (activity manager) 交互,并使用其 instrument 子命令来运行测试。

作为快捷方式,您可以启动 adb shell,调用 am instrument,并在同一输入行中指定命令行标记。shell 会在设备或模拟器上打开、运行您的测试、产生输出,然后返回到您计算机上的命令行。

要使用 am instrument 运行测试

  1. 构建或重新构建您的主应用程序和测试包。
  2. 将您的测试包和主应用程序 Android 包文件(APK 文件)安装到当前的 Android 设备或模拟器上。
  3. 在命令行中,输入

    adb shell am instrument -w <test_package_name>/<runner_class>

    其中 <test_package_name> 是您的测试应用程序的 Android 包名称,<runner_class> 是您正在使用的 Android 测试运行器类的名称。Android 包名称是您的测试包清单文件 (AndroidManifest.xml) 中 manifest 元素的 package 属性的值。

    Android 测试运行器类通常是 AndroidJUnitRunner

    adb shell am instrument -w com.android.example/androidx.test.runner.AndroidJUnitRunner

您的测试结果会出现在 STDOUT 中。

am instrument 标记

要查找可与 am instrument 命令一起使用的所有标记列表,请运行 adb shell am help。下表描述了一些重要的标记

表 2. 重要的 am instrument 标记

标志 描述
-w (无) 强制 am instrument 等待直到插桩终止后再自行终止。这会使 shell 保持打开状态,直到测试完成。查看测试结果需要此标记。
-r (无) 以原始格式输出结果。当您想要收集性能测量数据且不希望将其格式化为测试结果时,请使用此标记。此标记设计用于与 -e perf true 标记(在am instrument 选项部分有详细说明)配合使用。
-e <test_options> 以键值对的形式提供测试选项。am instrument 工具会使用指定的插桩类的 onCreate() 方法将其传递给该类。您可以多次指定 -e <test_options>。键和值在am instrument 选项部分中有详细说明。这些键值对只能与 AndroidJUnitRunnerInstrumentationTestRunner 及其子类一起使用。将它们用于任何其他类均无效。
--no-hidden-api-checks (无) 禁用对使用隐藏 API 的限制。有关什么是隐藏 API 以及它如何影响您的应用的更多信息,请阅读非 SDK 接口限制

am instrument 选项

am instrument 工具通过 -e 标记,以键值对的形式将测试选项传递给 AndroidJUnitRunnerInstrumentationTestRunner,语法如下

-e <key> <value>

某些键接受多个值。您可以在逗号分隔的列表中指定多个值。例如,此 AndroidJUnitRunner 调用为 package 键提供了多个值

adb shell am instrument -w -e package com.android.test.package1,com.android.test.package2 \
> com.android.test/androidx.test.runner.AndroidJUnitRunner

下表列出了您可以与测试运行器一起使用的键值对

表 3. 可与测试运行器一起使用的 -e 标记键值对

密钥 描述
package <Java_package_name> 测试应用程序中其中一个包的完全限定 Java 包名。将执行任何使用此包名的测试用例类。请注意,这不是 Android 包名;测试包具有单个 Android 包名,但在其内部可能包含多个 Java 包。
class <class_name> 其中一个测试用例类的完全限定 Java 类名。仅执行此测试用例类。
<class_name>#method name 完全限定的测试用例类名及其方法之一。仅执行此方法。请注意类名和方法名之间的井号 (#)。
func true 运行所有扩展了 InstrumentationTestCase 的测试类。
unit true 运行所有扩展 InstrumentationTestCasePerformanceTestCase 的测试类。
size [small | medium | large] 运行按大小注解的测试方法。注解为 @SmallTest@MediumTest@LargeTest
perf true 运行所有实现 PerformanceTestCase 的测试类。当您使用此选项时,请为 am instrument 指定 -r 标记,以便以原始格式保留输出,而不将其重新格式化为测试结果。
debug true 在调试模式下运行测试。
log true 加载并记录所有指定的测试,但不运行它们。测试信息会出现在 STDOUT 中。使用此选项可验证其他过滤条件和测试规范的组合。
emma true 运行 EMMA 代码覆盖率分析并将输出写入设备上的 /data/<app_package>/coverage.ec。要覆盖文件位置,请使用下条目中描述的 coverageFile 键。

注意:此选项需要测试应用程序的 EMMA 插桩构建版本,您可以使用 coverage 目标生成该版本。

coverageFile <filename> 覆盖设备上 EMMA 覆盖率文件的默认位置。以 UNIX 格式的路径和文件名指定此值。默认文件名在 emma 键的条目中说明。

使用 -e 标记时,请注意以下事项

  • am instrument 调用 onCreate(Bundle) 时会传入一个包含键值对的 Bundle
  • package 键优先于 class 键。如果您指定了一个包,然后又单独指定了该包中的一个类,Android 会运行包中的所有测试并忽略 class 键。
  • func 键和 unit 键是互斥的。

使用示例

以下部分提供了使用 am instrument 运行测试的示例。它们基于以下结构

  • 测试包的 Android 包名称为 com.android.demo.app.tests
  • 两个插桩测试类
    • TestClass1,其中包含测试方法 testMethod1
    • TestClass2,其中包含测试方法 testMethod2testMethod3
  • 测试运行器为 AndroidJUnitRunner

运行整个测试包

要运行测试包中的所有测试类,请输入

adb shell am instrument -w com.android.demo.app.tests/androidx.test.runner.AndroidJUnitRunner

运行测试用例类中的所有测试

要运行 TestClass1 类中的所有测试,请输入

adb shell am instrument -w  \
> -e class com.android.demo.app.tests.TestClass1 \
> com.android.demo.app.tests/androidx.test.runner.AndroidJUnitRunner

选择测试的子集

要运行 TestClass1 类中的所有测试以及 TestClass2 中的 testMethod3 方法,请输入

adb shell am instrument -w \
> -e class com.android.demo.app.tests.TestClass1,com.android.demo.app.tests.TestClass2#testMethod3 \
> com.android.demo.app.tests/androidx.test.runner.AndroidJUnitRunner

您可以在 AndroidJUnitRunner API 参考中找到更多用例。

查看统一测试报告

Android Gradle 插件提供了统一的测试报告任务,这些任务会生成合并了单元测试和插桩测试结果的 HTML 仪表板。

前提条件

  • Android Gradle 插件 9.2.0-alpha07 或更高版本。

要生成统一测试报告,请运行以下任务之一

报告范围 命令 描述 报告位置
当前模块 ./gradlew :module_name:createTestReport 为当前模块生成统一测试报告,合并单元测试和插桩测试结果。 path_to_your_project/module_name/build/reports/tests/test-report/
当前模块及依赖项 ./gradlew :module_name:createAggregatedTestReport 为当前应用模块及其库依赖项生成统一测试报告。 path_to_your_project/module_name/build/reports/tests/aggregated-test-report/