本文將在 GN 建構系統中,標準化 FIDL 測試的定義和整理方式,並達成下列目標:
- 命名時保持一致。如果 Rust 使用
fx test fidl_rust_conformance_tests,則 Go 應使用fx test fidl_go_conformance_tests。一致且可預測的命名方式可提供更優質的開發人員體驗。 - 執行所需作業。測試工作流程應能輕鬆執行單一測試元件,不必建構或執行任何額外項目。
- 在主機上執行。如有可能,測試應支援在主機 (非 Fuchsia) 上執行,因為編輯、建構及執行週期通常會快上許多。
- 遵循最佳做法。我們應遵循 Fuchsia 最佳做法,例如使用
fx test、建構元件等。
術語
本文使用下列術語:
- 目標:BUILD.gn 檔案中定義的 GN 目標
- toolchain:請參閱
fx gn help toolchain - 主機:開發人員的平台,具體來說是 Linux 或 Mac
- 裝置:Fuchsia 平台,可以是實體或模擬裝置 (即 qemu)
- 套件:Fuchsia 套件,Fuchsia 中的發布單位
- 元件:Fuchsia 元件,是 Fuchsia 中可執行的軟體單元
命名
一般指南:
- 請使用底線,不要使用連字號。
- 結尾名稱應為複數
_tests,而非單數_test。 - 為套件、元件和二進位檔使用完整、描述性且不重複的名稱。
最後一點是指偏好使用完整名稱 (例如 fidl_rust_conformance_tests),而非情境名稱 (例如 conformance_tests)。在目錄、套件、元件和二進位檔層級重複「fidl」和「rust」,似乎會顯得冗長且多餘。但事實是,這些名稱不得重複,最好以一致的方式確保名稱不重複,而不是記住奇怪的規則,例如 fidl-bindings-test 用於 Dart,fidl-test 用於 C。
名稱應使用下列配置,並以底線連結各部分:
tool [ bindings ] [ category [ subcategory ] ] tests
其中 tool 為下列其中一項:
- fidl:FIDL 執行階段支援
- fidlc:FIDL 編譯器前端
- fidlgen:FIDL 編譯器後端
- gidl、measure_tape 等:其他工具
其他部分包括:
- bindings
- c、cpp、cpp_wire、hlcpp、rust、go、dart 其中之一
- category、subcategory
- 例如:conformance、types、parser、lib
- 請勿使用:前端、後端、繫結 (工具會區分這些項目)
階層
定義測試的每個 BUILD.gn 檔案都應包含 "tests" 群組:
group("tests") {
testonly = true
deps = [ ... ] # not public_deps
}
如果目錄結尾為「tests」,且 BUILD.gn 檔案只定義測試目標,則群組應改為與目錄名稱相符。舉例來說,foo_tests/BUILD.gn 可以使用 group("foo_tests")。這會啟用 GN 標籤簡寫 //path/to/foo_tests,相當於 //path/to/foo_tests:foo_tests。
這些群組會匯總至父項目錄中 BUILD.gn 檔案的「tests」群組。根「tests」群組 (適用於部分程式碼集,例如 src/lib/fidl/BUILD.gn) 應包含在 bundles/fidl/BUILD.gn 中。這可讓 fx set ... --with //bundles/fidl:tests 在建構作業中納入所有 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,才能達到該目標,否則系統會嘗試為 Fuchsia 建構 GN:
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"
}
由於 tests.json 中的「name」欄位,因此可以執行 fx test fidl_bar_tests。
主機/裝置測試
在主機和裝置上執行的測試分為兩類。在第一個類別中,測試目標只會建構任一工具鍊。例如:
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
二進位檔。請勿使用這個方法,原因有二:
請改為編寫個別的 rustc_test 目標,並使用適當名稱:with_unit_tests
rustc_library("baz") {
...
}
rustc_test("fidl_baz_tests") {
...
}
分組
假設我們有下列測試結構:
- FIDL Rust
- 裝置
- 一致性
- 整合
- 主機
- 一致性
- 裝置
我們應該有葉子的測試目標:
fx test fidl_rust_conformance_testsfx 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