本文档规范了我们在 GN 中定义和组织 FIDL 测试的方式。 构建系统,并遵循以下目标:
- 名称一致。如果 Rust 使用
fx test fidl_rust_conformance_tests
, 那么 Go 应使用fx test fidl_go_conformance_tests
。一致且 可预测的命名方式可提供更好的开发者体验。 - 运行您需要的内容。测试工作流应能轻松运行 单个测试组件,而无需构建或运行任何额外内容。
- 在主机上运行。测试应尽可能支持在主机上运行 (非 Fuchsia),其中“编辑-构建-运行”的周期通常要短得多。
- 遵循最佳做法。我们应该遵循 Fuchsia 最佳实践,
使用
fx test
、 建筑物组件等
术语
本文档使用以下术语:
- target:在 BUILD.gn 文件中定义的 GN 目标
- 工具链:请参阅
fx gn help toolchain
- host:开发者的平台,特别是 linux 或 mac
- device:Fucsia 平台,可以是物理平台,也可以是模拟平台(即 qemu)
- package:Fuchsia 软件包;分布单位为 紫红色
- component:一个 Fuchsia 组件;可执行软件单元 紫红色
命名
通用准则:
- 请使用下划线,不要使用连字符。
- 以复数
_tests
而非单数_test
结束名称。 - 对软件包、组件和二进制文件使用完整的描述性唯一名称。
最后一点意味着建议你使用全名,例如 fidl_rust_conformance_tests
上下文名称,例如 conformance_tests
。这看起来可能很冗长
重复“fidl”是多余的和“锈”目录、软件包和组件
二进制数。但事实上,这些名称必须是唯一的,最好是
使它们以一致的方式与众不同,而不是记住诸如此类的奇怪规则
fidl-bindings-test
适用于 Dart,而 fidl-test
适用于 C。
名称应使用以下架构,使用下划线连接各个部分:
工具 [ bindings ] [ 类别 [ 子类别 ] ] 测试
其中,tool 可以是以下其中一项:
- fidl:FIDL 运行时支持
- fidlc:FIDL 编译器前端
- fidlgen:FIDL 编译器后端
- gidl、measure_tape 等:其他工具
其他部分包括:
- 绑定
<ph type="x-smartling-placeholder">
- </ph>
- c、cpp、cpp_wire、hlcpp、rust、go dart
- category、subcategory
<ph type="x-smartling-placeholder">
- </ph>
- 类别示例:conformance、types、parser、lib
- 请勿使用:frontend、backend、bindings (tool 区分这些内容)
层次结构
每个定义测试的 BUILD.gn 文件都应包含一个 "tests"
组:
group("tests") {
testonly = true
deps = [ ... ] # not public_deps
}
如果目录以“tests”结尾,且 BUILD.gn 文件仅定义 test
目标,则群组应与目录名称匹配。例如:
foo_tests/BUILD.gn 可以使用 group("foo_tests")
。这会启用 GN 标签
简写 //path/to/foo_tests
,相当于 //path/to/foo_tests:foo_tests
。
这些组汇总在“测试”中父级中的 BUILD.gn 文件组
目录。根“tests”(对于代码库的某些部分,例如
src/lib/fidl/BUILD.gn) 应包含在 bundle/fidl/BUILD.gn 中。这样一来,
fx set ... --with //bundles/fidl:tests
- 用于在 build 中包含所有 FIDL 测试。
(这些测试也会在 CQ 中运行,因为 //bundles/buildbot/core
包含
//bundles/fidl:tests
。)
二进制文件名称
通常,测试二进制文件名称基于目标名称。例如,
test("some_tests") { ... }
目标将生成一个 some_tests
二进制文件。
不过,对于单个测试,您通常需要多个目标(源代码集、
组件、软件包等)。因此,此部分中的示例
文档使用 some_tests_bin
等目标名称,并替换二进制文件名称
使用 output_name
参数:
test("some_tests_bin") {
output_name = "some_tests"
...
}
这也适用于 rustc_test
、go_test
等。
设备测试
假设我们有一个 :fidl_foo_tests_bin
目标,该目标会生成 fidl_foo_tests
二进制文件如需将此方法封装在软件包中,请使用 fuchsia_unittest_package
:
import("//build/components.gni")
fuchsia_unittest_package("fidl_foo_tests") {
deps = [ ":fidl_foo_tests_bin" ]
}
现在,我们可以按软件包名称或组件名称(两者相同)运行测试
尽在 fx test fidl_foo_tests
。
为每个测试使用单独的软件包。如果不相关的测试组件 捆绑在一个软件包中,运行其中一个测试会导致整个软件包 重建。只有在满足以下条件时,您才能将多个测试组件捆绑到一个软件包中: 一起进行测试,例如需要进行客户端和服务器集成测试请参阅 如需查看示例,请参阅复杂拓扑和集成测试。
如果您的测试需要任何组件功能、服务等,
fuchsia_unittest_component
默认值,您必须编写一个组件清单文件:
# BUILD.gn
import("//build/components.gni")
fuchsia_unittest_package("fidl_foo_tests") {
manifest = "meta/fidl_foo_tests.cml"
deps = [ ":fidl_foo_tests_bin" ]
}
# meta/fidl_foo_tests.cml
{
program: {
"binary": "bin/fidl_foo_tests"
},
use: [
{
protocol: [
"fuchsia.logger.LogSink", # some example services
"fuchsia.process.Launcher"
]
}
]
}
有关套件模板和组件模板的更多信息,请参见构建 组件。
主机测试
假设我们有一个 :fidl_bar_tests_bin
目标,该目标会生成 fidl_bar_tests
二进制文件我们必须确保 GN 在$host_toolchain
达到
target,否则它会尝试针对 Fuchsia 进行构建:
groups("tests") {
testonly = true
deps = [ ":fidl_bar_tests_bin($host_toolchain)" ]
}
(务必将 ($host_toolchain)
放入 BUILD.gn 文件的 tests
组中,而不是放在
//bundles/fidl:tests.)
这将创建一个名为 host_x64/fidl_bar_tests
的 test_spec 条目,
最终在 out/default/tests.json 中:
{
"command": [ "host_x64/fidl_bar_tests", "--test.timeout", "5m" ],
"cpu": "x64",
"label": "//PATH/TO/BAR:fidl_bar_tests_bin(//build/toolchain:host_x64)",
"name": "host_x64/fidl_bar_tests",
"os": "linux",
"path": "host_x64/fidl_bar_tests",
"runtime_deps": "host_x64/gen/PATH/TO/BAR/fidl_bar_tests_bin.deps.json"
}
由于“name”的原因,可以运行 fx test fidl_bar_tests
字段中的
tests.json.
主机/设备测试
同时在主机和设备上运行的测试分为两类。在第一个 则测试目标只需在任一工具链下构建即可。例如:
import("//build/components.gni")
rustc_test("fidl_rust_conformance_tests_bin") {
output_name = "fidl_rust_conformance_tests" # host test name
...
}
fuchsia_unittest_package("fidl_rust_conformance_tests") { # device test name
deps = [ ":fidl_rust_conformance_tests_bin" ]
}
group("tests") {
testonly = true
deps = [
":fidl_rust_conformance_tests_bin($host_toolchain)",
":fidl_rust_conformance_tests",
]
}
现在,我们可以通过两种方式运行测试:
- 在以下设备上:
fx test fidl_rust_conformance_tests --device
- 在以下主机上:
fx test fidl_rust_conformance_tests --host
第二类,设备测试和主机测试共享源代码,但它们
差异足够大,因此必须由单独的目标定义。这个
需要将主机测试定义封装在 if (is_host) { ... }
中,
GN 抱怨多个目标会产生相同的输出。例如:
import("//build/components.gni")
source_set("conformance_test_sources") {
...
}
test("fidl_hlcpp_conformance_tests_bin") {
output_name = "fidl_hlcpp_conformance_tests"
...
deps = [
":conformance_test_sources",
...
]
}
if (is_host) {
test("fidl_hlcpp_conformance_tests_bin_host") {
output_name = "fidl_hlcpp_conformance_tests" # host test name
...
deps = [
":conformance_test_sources",
...
]
}
}
fuchsia_unittest_package("fidl_hlcpp_conformance_tests") { # device test name
deps = [ ":fidl_hlcpp_conformance_tests_bin" ]
}
group("tests") {
testonly = true
deps = [
":fidl_hlcpp_conformance_tests_bin_host($host_toolchain)",
":fidl_hlcpp_conformance_tests",
]
}
现在,我们可以通过两种方式运行测试:
- 在以下设备上:
fx test fidl_hlcpp_conformance_tests --device
- 在以下主机上:
fx test fidl_hlcpp_conformance_tests --host
Rust 单元测试
Rust 库的定义如下:
rustc_library("baz") {
with_unit_tests = true
...
}
这会自动创建一个 baz_test
目标,用于构建 baz_lib_test
二进制文件请勿使用,原因有两个:
- 命名准则要求使用
_tests
后缀,而不是_test
。 - 可能会让人感到困惑,并且可能在 。
请编写一个单独的 rustc_test
目标,并使用with_unit_tests
适当的名称:
rustc_library("baz") {
...
}
rustc_test("fidl_baz_tests") {
...
}
分组
假设我们有以下测试结构:
- FIDL Rust
<ph type="x-smartling-placeholder">
- </ph>
- 设备
<ph type="x-smartling-placeholder">
- </ph>
- 一致性
- 集成
- 托管者
<ph type="x-smartling-placeholder">
- </ph>
- 一致性
- 设备
<ph type="x-smartling-placeholder">
我们应该为叶子设置测试目标:
fx test fidl_rust_conformance_tests
fx test fidl_rust_integration_tests
我们不应该为运行各部分的不同而额外创建软件包
测试。使用 fx test
,我们已经可以
- 运行所有测试:
fx test //path/to/fidl/rust
- 运行所有设备测试:
fx test //path/to/fidl/rust --device
- 运行所有主机测试:
fx test //path/to/fidl/rust --host