FX 测试用户指南

本页面提供了有关使用 fx test 命令在 Fuchsia 源代码检出设置 (fuchsia.git) 中运行测试的最佳实践、示例和参考资料。

基本用法

如需开始使用,只需运行 fx test

fx test

此操作将执行以下几项操作:

  1. 确定当前 build 中包含的测试。
  2. 根据选择条件选择一部分纳入的测试。
  3. 重新构建并重新发布这些测试。
  4. 检查是否存在合适的 Fuchsia 设备来运行测试。
  5. 同时,开始在该设备上运行测试并提供状态输出。
  6. 写入描述所发生操作的日志文件。

如果您未在 build 中包含任何测试,fx test 将退出。在 fx set 命令行中尝试使用 fx set core.x64--with //src/diagnostics:tests,以包含一些测试作为示例。

如需详细了解 fx test 的当前状态,请参阅此 README 页面。

基本概念

fx test 是一个测试执行器,这意味着它会接收可用测试的列表,并负责安排和观察这些测试的执行情况。此数据的来源为 tests.json

tests.json 中列出的每个测试都是一个测试套件,每个测试套件可能包含任意数量的测试用例。也就是说,测试套件是单个二进制文件或 Fuchsia 组件,其中包含以特定于每个测试框架的方式(例如 C++ TEST、Rust #[test]、Python unittest.TestCase)定义的测试用例。枚举和执行设备上的测试用例是测试运行程序框架的责任。

基本测试选择

fx test 支持使用命令行选项选择单个测试套件。这样,您就可以在 build 中包含大量测试,然后仅执行这些测试的子集。

传递给 fx test 的任何非标志实参都是一个选择,系统会针对输入中的每个测试对该选择进行模糊匹配:

fx test archivist --dry

默认情况下,系统会搜索以下字段:

字段 说明
名称 测试的完整名称。这是设备端测试的组件网址,也是主机测试的测试二进制文件路径。
标签 测试的 build 标签。例如,//src/examples:my_test
组件名称 仅用于设备端测试的组件清单名称(不包括 .cm)。
软件包名称 仅用于设备端测试的 Fuchsia 软件包的名称。

您可以通过列出前缀来选择源代码树中某个目录下的所有测试:

fx test //src/diagnostics/tests --dry

默认情况下,系统会匹配上述所有字段,但您可以使用 --package--component 选择特定字段:

fx test --package archivist_unittests --dry

默认情况下,命令行上的多个选择项会实现包含性 OR 操作。测试选择支持复合 AND 操作,如下所示:

fx test --package archivist --and unittests --dry

此命令会选择软件包与 archivist 匹配且任何字段与 unittests 匹配的所有测试。

如果您知道要执行的测试的确切名称,可以使用 --exact 标志仅选择该测试:

fx test --exact fuchsia-pkg://fuchsia.com/archivist-tests#meta/archivist-unittests.cm --dry

如果没有测试与您的选择匹配,fx test 将尝试以启发式方式匹配源代码签出中的测试,并建议包含这些测试的 fx set 实参:

$ fx test driver-tests --dry
...
For `driver-tests`, did you mean any of the following?

driver_tools_tests (91.67% similar)
    --with //src/devices/bin/driver_tools:driver_tools_tests
driver-runner-tests (90.96% similar)
    --with //src/devices/bin/driver_manager:driver-runner-tests
driver-inspect-test (90.96% similar)
    --with //src/devices/tests/driver-inspect-test:driver-inspect-test

然后,您可以将必要的软件包添加到 build 中。

基本测试输出

fx test 将其输出存储在日志文件中,以供日后分析。您可以使用 -pr/--previous 实参以文本形式查看此日志文件的摘要。例如,如需查看上次运行的测试日志,请执行以下操作:

$ fx test -pr log
previous-log-file.json.gz:

4 tests were run

[START first_test]
...
[END first_test]

如需查看用于处理之前日志文件的完整选项列表,请运行 fx test -pr help

默认情况下,此命令会处理存储在 Fuchsia 输出目录中的最新日志,但您可以传递 --logpath 来选择特定日志。

此命令可应对损坏或不完整的日志文件,因此即使您终止运行测试的 fx test 命令,此命令也应仍能正常运行。

基本测试调试

fx testzxdb 集成,提供了一种简单易用的方式来调试测试失败,而无需重新编译任何内容。将 --break-on-failure 传递给 fx test 调用,以便在测试失败时自动中断到调试器中:

$ fx test --break-on-failure rust_crasher_test.cm
...
⚠️  zxdb caught test failure in rust_crasher_test.cm, type `frame` to get started.
   14 LLVM_LIBC_FUNCTION(void, abort, ()) {
   15   for (;;) {
 ▶ 16     CRASH_WITH_UNIQUE_BACKTRACE();
   17     _zx_process_exit(ZX_TASK_RETCODE_EXCEPTION_KILL);
   18   }
══════════════════════════
 Invalid opcode exception
══════════════════════════
 Process 1 (koid=107752) thread 1 (koid=107754)
 Faulting instruction: 0x4159210ab797

🛑 process 1 __llvm_libc::__abort_impl__() • abort.cc:16
[zxdb] // Now you can debug why the test failed!

您还可以使用 --breakpoint=<location> 选项在代码中的任何特定位置设置断点。<location> 采用标准的 zxdb 断点语法,通常是文件和行号或函数名称:

  • --breakpoint=my_file.rs:123 在 my_file.rs 的第 123 行设置断点。
  • --breakpoint=some_functionsome_function 上设置断点。

请注意,此选项会导致测试运行速度明显变慢,因为 zxdb 需要加载测试的所有符号才能安装断点。强烈建议仅在 --test-filter 的基础上使用此选项。

调试完测试失败问题后,您可以输入 quitctrl+ddetach * 来继续运行测试。请注意,如果存在多个测试用例失败,系统不会暂停,以便您调试这些测试。如需详细了解如何调试并行发生的多个测试失败,请参阅调试测试

配置选项

fx test 可高度配置,如需查看完整的选项列表,请访问 fx test --help

本部分介绍了如何指定配置选项以及这些选项的含义。配置选项分为实用程序、构建、测试选择、执行或输出选项。它们可以在命令行中指定,也可以在配置文件中指定。

配置文件

fx test 的所有实参都在命令行上设置,但可以为每个用户设置默认值。如果您在 HOME 目录中放置一个名为 .fxtestrc 的文件,则该文件中的实参将成为未来 fx test 调用中的新默认实参。

例如:

# ~/.fxtestrc
# Lines starting with "#" are comments and ignored.
# The below config roughly matches the behavior of the old Dart-based `fx test`.

# Default parallel to 1.
--parallel 1

# Disable status output.
--no-status

# Print output for tests taking longer than 2 seconds.
--slow 2

上述文件替换了 --parallel--status 标志的默认值,这两个标志的默认值通常分别为 4false。在调用 fx test 时,仍可在命令行中替换新的默认值。

实用程序选项

实用程序选项会改变 fx test 的整体行为。

--dry 执行“试运行”。fx test 将完成测试选择,但随后只会打印所选测试套件的列表,而不会执行任何测试套件。

--list 以“列表模式”运行 fx test。此命令不会执行测试,而是列出每个测试套件中的所有测试用例。它会输出相应的命令行来运行每个单独的测试用例。 请注意,这需要访问 Fuchsia 设备或模拟器,因为测试用例是由设备上的测试管理器枚举的。

-pr/--prev/--previous COMMAND 将处理之前执行 fx test 时生成的日志文件,并根据 COMMAND 的值输出信息。不执行任何新测试。 此命令会遵循 --logpath 来指定要读取的日志。

实现了以下 COMMAND

  • log 会输出日志文件中记录的每项测试的命令行和输出。
  • path 会输出最新日志文件的路径。
  • replay 将使用新的显示选项重放上一次跑步。 可以使用 --replay-speed 实参控制重放速度。值 > 1 会加快输出速度,而值 < 1 会以慢动作显示跑步。
  • help 用于输出可用命令的摘要。

构建选项

fx test 默认构建和更新所选测试。在运行 fx -i test 时,此标志非常有用,它会检测源目录中的更改,并在每次修改文件后重新调用 fx test。测试重建按如下方式进行(覆盖变量内嵌列出)。

  • 通过为每个 fx test 调用 fx build <targets> 来重建所有选定的测试。
    • 使用 --[no-]build 可切换此行为。
  • 如果所选测试位于 build 的指定软件包中(使用 fx set --with-test 指定),则会构建 updates 软件包并执行 OTA。
    • 使用 --[no-]updateifinbase 可切换此行为。
    • 警告:以模拟器为目标平台时,OTA 将失败。

测试选择选项

以下选项会影响 fx test 选择的测试以及选择的应用方式。

--host--device 分别仅选择主机测试或设备测试。这是全局设置,无法组合使用。

--[no-]e2e 用于控制是否运行端到端 (E2E) 测试。 默认情况下,系统不会运行 E2E 测试,因为这些测试可能会使设备处于无效状态。--only-e2e 表示 --e2e,并确保仅选择 E2E 测试。

--package (-p) 和 --component (-c) 分别用于在软件包或组件名称中进行选择。名称前面没有“select”的任何测试字段。 您可以使用 --and (-a) 更改多个选择。例如:

fx test --package foo -a --component bar //src/other --and --package my-tests

上述命令行包含两个选择子句:

  1. 软件包“foo”和组件“bar”(例如 fuchsia-pkg://fuchsia.com/foo#meta/bar.cm)。
  2. 软件包“my-tests”和 //src/other。

系统会选择符合上述任一子句的测试。

默认情况下,测试选择会使用 Damerau-Levenshtein 距离 3 进行模糊匹配(例如,“my_tset”将匹配“my-test”)。--fuzzy <N> 可用于将此值替换为 N,其中 0 表示不进行模糊匹配。

如果没有测试与选择子句匹配,则默认显示建议。您可以使用 --suggestions-count N 替换建议数量(默认值为 6),并使用 --[no-]show-suggestions 停用或启用建议。

执行选项

测试以特定方式执行,可最大限度提高吞吐量和稳定性,但此默认设置的每个元素都可以被替换。测试按如下方式执行(替换项以内嵌方式列出):

  • 每个选定的测试都按照其在 tests.json 中的显示顺序执行
    • 使用 --random 可随机化此执行顺序。
  • 系统会运行所有选定的测试,从上面有序列表的开头开始。
    • 使用 --offset N 跳过列表开头的 N 个测试。默认值为 0。
    • 使用 --limit N 从偏移量开始运行最多 N 个测试。默认值为无限制。
  • 最多可并行运行 4 个测试,其中最多 1 个测试是“非密封”测试(由 test-list.json 确定)。
    • 使用 --parallel N 更改此默认值。--parallel 1 表示按顺序执行每个测试。
  • 测试会一直运行,直到自行终止。
    • 使用 --timeout N 可为每个测试设置最多 N 秒的等待时间。
  • 每项测试运行一次。
    • 使用 --count N 运行每项测试 N 次。
  • 每个测试都会运行所有测试用例。
    • 使用 --test-filter 仅运行指定名称的测试用例。
  • 系统会记录失败的测试,并继续执行下一个选定的测试。
    • 使用 --fail (-f) 在首次失败后终止所有测试。
  • 如果看到严重程度更高的日志,在 tests.json 中指定了最大日志级别的测试将会失败。
    • 使用 --[no-]restrict-logs 可切换此行为。
  • 测试组件本身会选择要发出的最低日志严重性。
    • 使用 --min-severity-logs 可针对所有测试组件替换此最小值。
  • 测试组件使用 build 制品的 Merkle 根哈希运行,这可确保最新构建版本已成功推送到目标设备并正在运行。
    • 使用 --[no-]use-package-hash 可切换此行为。
  • 已停用的测试用例不会运行。
    • 使用 --also-run-disabled-tests 仍可运行已停用的测试用例。
  • 测试输出日志仅包含组件 moniker 的最后一段,因此更易于直观检查。
    • 使用 --[no-]show-full-moniker-in-logs 可切换此行为。
  • 失败的测试会在失败后立即终止,无需等待

    • 使用 --break-on-failure 通过 zxdb 捕获失败的测试。
    • 使用 --breakpoint=<location> 在特定位置安装断点。

    请注意,使用 --breakpoint 选项会显著减慢测试速度。强烈建议仅将此选项与 --test-filter 结合使用。--break-on-failure 可用于许多测试,对性能的影响极小。

  • 测试的命令行实参完全由测试运行程序控制

    • -- 附加到您的实参,以将剩余实参原封不动地传递给测试。例如:fx test foo -- --argument_for_test 会将 --argument_for_test 传递给测试本身。
  • 宿主测试将自动从用户环境中继承一组有限的环境变量

    • 使用 --env (-e) 向测试添加新的 KEY=VALUE 环境变量。此标志可以多次指定。
  • 如果没有正在运行的软件包服务器,系统会在 fx test 执行期间启动临时服务器

    • 使用 --no-allow-temporary-package-server 可停用此行为。
    • 如果找到现有的软件包服务器,则不会启动临时服务器。

输出选项

fx test 适用于开发者用例,包含一个简单的终端界面,用于显示测试的执行状态。默认输出行为如下(覆盖项内嵌列出):

  • 终端底部会显示状态,并自动更新以显示当前正在执行的操作。
    • 使用 --[no-]status 切换状态显示。
    • 使用 --status-lines N 更改状态输出行的数量。
    • 使用 --status-delay N 更改刷新频率(默认值为 0.033,即大约 30 Hz)。如果您的终端运行缓慢,您可能需要将此值更改为 0.5 或 1。
  • 输出采用 ANSI 终端颜色设置样式。
    • 使用 --[no-]style 可切换此行为。
    • 使用 --simple 作为 --no-style --no-status 的简写形式。
  • 测试输出仅针对失败的测试显示。
    • 使用 --output (-o) 显示所有测试输出(与 --parallel 1 结合使用可防止交错)。
    • 使用 --no-output 可明确隐藏输出,例如覆盖配置中设置的 --output
    • 使用 --slow N (-s N) 仅显示执行时间超过 N 秒的测试套件的输出。
  • 日志会写入 fx status 指定的 build 目录下的带时间戳的 .json.gz 文件中。
    • 使用 --[no-]log 可完全切换日志记录功能。
    • 使用 --logpath 更改日志的输出路径。
  • 测试工件不会从设备流式传输。
    • 使用 --artifact-output-directory (--outdir) 指定一个目录,用于以 ffx test 输出格式流式传输工件。
  • 调试打印已抑制。
    • 使用 --verbose (-v) 将调试信息输出到控制台。 此数据非常详细,仅对调试 fx test 本身有用。

日志格式

fx test 旨在通过将每个用户可见的输出表示为在执行期间记录到文件中的“事件”,来支持外部工具。

日志文件使用 gzip 进行压缩。解压缩后的文件的每一行都是一个 JSON 对象,表示一个事件。事件架构目前在 Python 文件中定义。

当该格式稳定后,就可以构建交互式查看器和转换器,将其转换为其他格式(例如构建事件协议)。

常见问题

fx test 无法与 emacs 搭配使用

emacs 编译窗口不模拟兼容 xterm 的终端,从而导致如下错误:

in _make_progress_bar raise ValueError("Width must be at least 3")

如需解决此问题,请运行 fx test 并使用 --no-status 选项来停用状态栏。

转义序列显示在 fx 测试输出中

您的终端可能不支持 ANSI 颜色代码,而 fx test 未能检测到这一点。

--no-style 选项传递给 fx test 以停用颜色输出,或将 --no-status 选项传递给 fx test 以停用更新状态栏。将 --simple 选项传递给 fx test 等同于 --no-style --no-status

我不知道我的日志文件在哪里

您可以通过将 --logpath 传递给 fx test 来设置日志的位置,不过建议仅在非交互式使用时这样做。

默认情况下,日志会以带时间戳的文件形式存储在 Fuchsia 输出目录中。使用 fx test -pr path 输出之前日志的路径。

打印日志文件会将垃圾内容转储到我的终端中

默认情况下,fx test 日志会进行 gzip 压缩。使用以下命令将最新日志以美观的格式输出到终端:

cat `fx test -pr path` | gunzip | jq -C | less -R

此命令执行以下操作:

  • 找到最新的日志路径 (fx test -pr path)。
  • 将日志通过管道传输到 gunzip 以解压缩日志。
  • 将解压缩的日志通过管道传输到 jq,以使用彩色输出 (-C) 对其进行美化打印。
  • 将颜色输出通过管道传输到配置为显示颜色 (-R) 的 less

为方便起见,您可以在 .bashrc 文件中为此命令添加别名:

alias testlog='cat `fx test -pr path` | gunzip | jq -C | less -R'

选择停用新的 fx 测试命令

新的 fx test 命令目前设置为默认命令。

如需选择不启用此设置,请设置以下环境变量:

export FUCHSIA_DISABLED_legacy_fxtest=0