本文简要介绍了 Test Mapping,并说明了如何在 Android 开源项目 (AOSP) 中开始配置测试。
Test Mapping 简介
Test Mapping 是一种基于 Gerrit 的方法,让开发者能够直接在 Android 源代码树中创建提交前和提交后测试规则,并将要测试的分支和设备的决策留给测试基础架构。Test Mapping 定义是名为 TEST_MAPPING
的 JSON 文件,该文件可放置在任何源目录中。
Atest 可以使用 TEST_MAPPING
文件在相关目录中运行提交前测试。借助 Test Mapping,您只需在 Android 源代码树中进行最少的更改,即可将同一组测试添加到提交前检查。
请参阅以下示例:
Test Mapping 依赖于 Trade Federation (TF) 自动化测试框架来进行测试执行和结果报告。
定义测试组
Test Mapping 通过测试组对测试进行分组。测试组的名称可以是任何字符串。例如,presubmit 可以是在验证更改时运行的测试组的名称。postsubmit 测试可在更改合并后用于验证 build。postsubmit
打包构建脚本规则
为了让 Trade Federation 自动化测试框架针对指定 build 运行测试模块,必须针对 Soong 将这些模块的 test_suites
(或者针对 Make 将这些模块的 LOCAL_COMPATIBILITY_SUITE
)设为以下两个套件之一:
general-tests
适用于不依赖于设备专用功能(例如大多数设备不包含的、供应商专用的硬件)的测试。大多数测试都应该在general-tests
套件中,即使它们针对一个 ABI、位数或 HWASan 等硬件功能(每个 ABI 都有一个单独的test_suites
目标),并且即使它们必须在设备上运行。device-tests
适用于取决于设备专用功能的测试。通常,这些测试位于vendor/
下。设备专用仅指设备专有的功能,因此这适用于 JUnit 测试以及 GTest 测试(即使它们是 ABI 专用,通常也应标记为general-tests
)。
示例:
Android.bp: test_suites: ["general-tests"],
Android.mk: LOCAL_COMPATIBILITY_SUITE := general-tests
配置在测试套件中运行的测试
如需在测试套件中运行测试,该测试:
- 不得包含任何 build 提供程序。
- 必须在完成之后进行清理,例如,删除测试期间生成的任何临时文件。
- 必须将系统设置更改为默认设置或原始值。
不应假定设备处于特定状态下,例如 root 准备就绪状态。 大多数测试无需 root 权限即可运行。如果测试需要 root 权限,应通过
AndroidTest.xml
中的RootTargetPreparer
指定该权限,如以下示例所示:<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
创建 Test Mapping 文件
对于需要测试覆盖率的目录,请添加与示例类似的 TEST_MAPPING
JSON 文件。这些规则可以确保当此目录或其子目录中的任何文件被访问时,测试会在提交前检查中运行。
示例
以下是 TEST_MAPPING
文件示例(该文件采用 JSON 格式,但支持注释):
{
"presubmit": [
// JUnit test with options and file patterns.
{
"name": "CtsWindowManagerDeviceTestCases",
"options": [
{
"include-annotation": "android.platform.test.annotations.RequiresDevice"
}
],
"file_patterns": ["(/|^)Window[^/]*\\.java", "(/|^)Activity[^/]*\\.java"]
},
// Device-side GTest with options.
{
"name" : "hello_world_test",
"options": [
{
"native-test-flag": "\"servicename1 servicename2\""
},
{
"native-test-timeout": "6000"
}
]
}
// Host-side GTest.
{
"name" : "net_test_avrcp",
"host" : true
}
],
"postsubmit": [
{
"name": "CtsDeqpTestCases",
"options": [
{
// Use regex in include-filter which is supported in AndroidJUnitTest
"include-filter": "dEQP-EGL.functional.color_clears.*"
}
]
}
],
"imports": [
{
"path": "frameworks/base/services/core/java/com/android/server/am"
}
]
}
设置特性
在示例中,presubmit
和 postsubmit
分别是每个测试组的名称。如需详细了解测试组,请参阅定义测试组。
您可以在 name
属性值中设置测试模块的名称或 Trade Federation 集成测试名称(指向测试 XML 文件的资源路径,例如 uiautomator/uiautomator-demo
)。请注意,name
字段不能使用类 name
或测试方法 name
。如需缩减要运行的测试,请使用 include-filter
等选项。请参阅 include-filter
用法示例。
测试的 host
设置指示测试是否是在主机上运行的无设备测试。默认值为 false
,表示需要有设备才能运行测试。受支持的测试类型包括 HostGTest
(适用于 GTest 二进制文件)和 HostTest
(适用于 JUnit 测试)。
使用 file_patterns
属性,您可以设置正则表达式字符串列表,以匹配任何源代码文件的相对路径(相对于包含 TEST_MAPPING
文件的目录)。在示例中,只有当 Java 文件以 Window
或 Activity
开头,并且该文件存在于与 TEST_MAPPING
文件相同的目录或其任何子目录中时,测试 CtsWindowManagerDeviceTestCases
才会在提交前测试中运行。JSON 文件中的反斜杠 (\) 需要进行转义。
借助 imports
属性,您可以包含其他 TEST_MAPPING
文件中的测试,而无需复制内容。导入路径的父级目录中的 TEST_MAPPING
文件也包含在内。Test Mapping 支持嵌套导入;这意味着两个 TEST_MAPPING
文件可以互相导入,并且 Test Mapping 能够合并随附测试。
options
属性包含其他 Tradefed 命令行选项。
要获取指定测试可用选项的完整列表,请运行以下命令:
tradefed.sh run commandAndExit [test_module] --help
如需详细了解各选项的工作原理,请参阅 Tradefed 中的选项处理。
使用 Atest 运行测试
要在本地执行提交前测试规则,请执行以下操作:
- 前往包含
TEST_MAPPING
文件的目录。 运行以下命令:
atest
在当前目录及其父目录的 TEST_MAPPING
文件中配置的所有提交前测试都会运行。Atest 会针对提交前测试找到两个测试(A 和 B)并加以运行。
这是运行当前工作目录 (CWD) 和父级目录中的 TEST_MAPPING
文件中的提交前测试的最直接方法。Atest 会找到 CWD 及其所有父级目录中的 TEST_MAPPING
文件并使用这些文件。
构建源代码
以下示例展示了如何在源代码树中配置 TEST_MAPPING
文件:
src
├── project_1
│ └── TEST_MAPPING
├── project_2
│ └── TEST_MAPPING
└── TEST_MAPPING
src/TEST_MAPPING
的内容:
{
"presubmit": [
{
"name": "A"
}
]
}
src/project_1/TEST_MAPPING
的内容:
{
"presubmit": [
{
"name": "B"
}
],
"postsubmit": [
{
"name": "C"
}
],
"other_group": [
{
"name": "X"
}
]}
src/project_2/TEST_MAPPING
的内容:
{
"presubmit": [
{
"name": "D"
}
],
"import": [
{
"path": "src/project_1"
}
]}
指定目标目录
您可以指定一个目标目录,以便运行该目录中 TEST_MAPPING
文件中的测试。以下命令可运行两个测试(A、B):
atest --test-mapping src/project_1
运行提交后测试规则
您还可以使用该命令运行在 src_path
(默认为 CWD)及其父目录中的 TEST_MAPPING
中定义的提交后测试规则:
atest [--test-mapping] [src_path]:postsubmit
仅运行不需要设备的测试
要想仅运行针对主机配置的不需要设备的测试,可以为 Atest 使用选项 --host
。如果没有此选项,Atest 将运行两种测试,即需要设备的测试和在主机上运行的不需要设备的测试。这两种测试分别在两个独立的套件中运行:
atest [--test-mapping] --host
识别测试组
您可以在 Atest 命令中指定测试组。以下命令可运行与 src/project_1
目录中的文件相关的所有 postsubmit
测试,其中只包含一个测试 (C)。
或者,您也可以使用 :all
来运行所有测试(无论测试属于哪个组)。以下命令可运行四个测试(A、B、C、X):
atest --test-mapping src/project_1:all
包含子目录
默认情况下,如果使用 Atest 运行 TEST_MAPPING
中的测试,那么系统仅会运行在 CWD(或指定目录)及其父目录中的 TEST_MAPPING
文件中配置的提交前测试。如果要运行子目录中的所有 TEST_MAPPING
文件中的测试,请使用 --include-subdir
选项强制要求 Atest 将这些测试包含在内。
atest --include-subdir
如果未使用 --include-subdir
选项,Atest 将仅运行测试 A。如果使用了 --include-subdir
选项,Atest 将运行两个测试(A、B)。
支持行级注释
您可以添加行级 //
格式的注释,以使用后面的设置描述来充实 TEST_MAPPING
文件。ATest 和 Trade Federation 会将 TEST_MAPPING
预处理为不带注释的有效 JSON 格式。为了使 JSON 文件简洁易读,仅支持行级 //
格式的注释。
示例:
{
// For presubmit test group.
"presubmit": [
{
// Run test on module A.
"name": "A"
}
]
}