设计初衷
软件测试是一种常见做法,可帮助团队持续交付 质量代码。测试对软件行为、捕获和 防止功能或其他所需属性出现衰退,并帮助扩展 工程流程。
衡量测试覆盖率的源代码行覆盖率有助于工程师 找出测试解决方案中的不足之处使用测试覆盖率作为指标 推动实现更高质量的软件和更安全的开发实践。测量测试 帮助工程师保持较高的质量水准。
测试覆盖率并不保证代码不会出现错误。测试应该与 模糊测试、静态和动态测试等其他工具 分析等
绝对测试覆盖率
绝对测试覆盖率衡量的是所涵盖的所有源代码行 测试。Fuchsia 的持续集成 (CI) 基础架构会生成绝对覆盖率报告, 。覆盖率报告通常最多会在几个小时前过时。
绝对覆盖率信息中心
点击此处可查看最新的绝对覆盖率报告。 此信息中心以树形布局显示发现的所有代码 作为源代码树的一个子集,包含在经过的所有测试中。您 可以按目录结构浏览树,并查看总覆盖率指标 。
此外,覆盖范围信息还会作为 Google 的 内部代码搜索。
增量测试覆盖率
增量测试覆盖率会在 Gerrit 代码审核网页界面。增量覆盖率显示,尤其是在 给定更改的上下文,其中修改后的行将用于测试和 修改后的代码行。
增量测试覆盖率由 Fuchsia 的提交队列 (CQ) 收集 基础架构将更改发送到 CQ (Commit-Queue+1) 时,您可以点击 “检查”部分标签页,然后在三点状菜单下点击“显示其他结果” 然后在过滤条件文本框中输入“fuchsia-coverage”找到那个名为 负责收集要在 Gerrit 中展示的增量覆盖率。当 tryjob 完成,您的补丁集应具有绝对覆盖率 (|Cov.|), 增量覆盖率(升幅)
对于影响项目的更改,保持较高的增量测试覆盖率有助于 持续保持较高的测试覆盖率。特别是,它可以防止引入新的 将未经测试的代码复制到项目中更改作者可以查看增量覆盖率 更改相关信息,以确保测试范围足够大。 代码审核人员可以查看关于更改的增量测试覆盖率信息, 请作者弥补所有他们认为重要的测试缺口。
覆盖率驱动型开发工作流
您可以在浏览器或 VS Code 中查看本地修改的覆盖率。 您可以使用它来建立覆盖率驱动型开发工作流。
准备测试环境
首先,配置构建以使用覆盖率变体并包含 这些示例将用于演示该工作流。
C++
fx set core.x64 --variant coverage --with examples/hello_world
fx build
Rust
fx set core.x64 --variant coverage-rust --with examples/hello_world
fx build
让我们启动一个作为您的目标设备的模拟器,然后启动 我们将使用两个终端来完成此步骤。如果您已有 无论是模拟器还是真实硬件,则可以跳过 此步骤。
在您的第一个终端中:
fx qemu -kN
接下来,启动软件包服务器,用于发布 测试软件包,此过程将在后台运行。如果你已经运行了一个软件包服务器,则可以跳过 此步骤。
在第二个终端中:
fx serve
在浏览器中查看覆盖率
在此工作流程中,我们将运行测试并生成覆盖率报告, 。
执行测试并导出覆盖率 HTML 报告
执行测试并生成 HTML 报告。
C++
fx coverage --html-output-dir $HOME/fx_coverage hello-world-cpp-unittests
Rust
fx coverage --html-output-dir $HOME/fx_coverage hello-world-rust-tests
在浏览器中查看覆盖率摘要
使用浏览器打开 $HOME/fx_coverage/index.html
。您应该会看到覆盖率选项
摘要页面。
点击任一文件即可查看该文件的行覆盖率。通过 “计数”列显示的是测试行被访问的次数(1 次或多次)。否 “计数”的值表示 0,即未覆盖该行。
在 VS Code 中查看覆盖率
只有在准备好测试环境后才能开始本部分。
- 从 Visual Studio Marketplace 安装 coverage-gutters 扩展程序。
- 通过将以下属性添加到
settings.json
。
{
"coverage-gutters.coverageBaseDir": ".",
"coverage-gutters.showLineCoverage": true,
"coverage-gutters.coverageFileNames": [ "lcov.info" ]
}
运行测试并查看覆盖率
我们来执行测试并导出 LCOV 文件,VS Code 将使用该文件显示 覆盖率。
C++
fx coverage --lcov-output-path $FUCHSIA_DIR/lcov.info hello-world-cpp-unittests
Rust
fx coverage --lcov-output-path $FUCHSIA_DIR/lcov.info hello-world-rust-tests
在 VS Code 中查看覆盖率
- 找到您要查看其覆盖率的文件。
- 右键点击文件的修改区域,然后选择“Coverage Gutters: Display [覆盖范围:显示间距] 覆盖率。”
- 已覆盖的线条为绿色,未覆盖的线条为红色。
- 您可以重新导出 LCOV 并重新执行第 2 步,以查看更新后的覆盖率(对于某些 因为“watch”不起作用。)
针对更改重新运行测试
最后,您可以使用此命令来监控文件系统更改并重新运行 都会在每次保存代码时都自动进行测试
C++
fx -i coverage --lcov-output-path $FUCHSIA_DIR/lcov.info hello-world-cpp-unittests
Rust
fx -i coverage --lcov-output-path $FUCHSIA_DIR/lcov.info hello-world-rust-tests
端到端 (E2E) 测试排除项
只有单元测试和封闭集成测试被视为可靠来源 测试覆盖率。对于端到端测试,系统不会收集或显示测试覆盖范围。
E2E 测试是指对整个产品进行测试的大型系统测试, 必须涵盖源代码中明确定义的部分。例如, 在 Fuchsia 上进行 E2E 测试的常见方式,以便在模拟器中启动系统, 并期望某些行为。
原因
由于 E2E 测试会将系统作为一个整体来进行测试:
- 观察到它们经常会在运行之间触发不同的代码路径,因此 其覆盖率也会导致不稳定
- 它们经常会在覆盖率构建器上超时,从而导致构建器不稳定。端到端 测试的运行速度远远慢于单元测试和小型集成测试, 通常需要几分钟才能完成。此外,它们在覆盖率构建器上的运行速度甚至会更慢 而过度耗用资源。
具体做法
对于顶级 buildbot 软件包(例如 core
),
提供了副本 core_no_e2e
,因此聊天机器人
可以使用 no_e2e
软件包来避免构建和运行
所有 E2E 测试
目前,没有可靠的方法来识别树内的所有 E2E 测试。作为
代理,no_e2e
软件包会保持不变,即它们没有任何已知
通过 GN 的 e2e 测试库的递归依赖项中的 e2e 测试
assert_no_deps
。端到端测试库列表
它经过人工挑选和维护,并假设环境变化非常大
频率:
e2e_test_libs = [
"//sdk/testing/sl4f/client",
"//third_party/mobly($host_toolchain)",
"//src/testing/end_to_end/honeydew($host_toolchain)",
]
if (is_linux) {
e2e_test_libs += [ "//tools/emulator($host_toolchain)" ]
}
限制
目前,只有在满足以下条件时,系统才会收集测试覆盖率:
- 代码使用 C、C++ 或 Rust 编写。
- 该代码会在用户模式下在 Fuchsia 上运行,或在主机上运行。内核覆盖率 尚不支持(跟踪错误)。
- 该测试在 qemu 上运行。尚不支持在硬件上进行测试。
- 该测试作为
core
产品配置的一部分运行。 - 不支持端到端 (e2e) 测试。
最后要注意的是,e2e 测试在整个系统中会执行大量代码, 它们的运行方式不一致(或“不稳定”)。为了实现 代码测试覆盖率更高,但实际上建议这样做 使用单元测试和集成测试
实验功能
默认情况下,系统仅收集增量覆盖率
在 core.x64
中。针对两个core.x64
中的更改收集合并覆盖率
和 core.arm64
,请按以下步骤操作:
- 在 Gerrit 中,转到“Checks”标签页。
- 按“选择 tryjobs”。
- 添加了
fuchsia-coverage-x64-arm64
。
系统会显示一个对勾。待其从待处理状态变为已完成状态后,刷新 Gerrit 即可看到 覆盖率结果。
另请参阅: 问题 91893:仅在 Gerrit 中针对 x64 收集增量覆盖率
即将发布的功能
对以下附加用例的支持目前正在开发中:
- 内核代码覆盖率。
- 涵盖除
core
以外的产品配置,例如bringup
或workstation_eng
。 - 硬件目标的覆盖率,即从不在测试中运行的测试收集数据 qemu。
问题排查
不支持的配置 / 语言 / 运行时
如果您看不到绝对或增量覆盖率信息, 请先查看限制,并确保您的代码 预计首先获得保修支持
为帮助您排查问题,请检查是否缺少覆盖率(各行应 已覆盖但显示为未覆盖)或者您是否未覆盖 信息(任何文件都不会显示在覆盖率报告中,或者行是 未对这些内容是否涵盖加注注释)。
缺少覆盖率表示代码是使用插桩构建的,但 实际上并未包含在运行的测试中。可能没有任何覆盖率信息 例如,表明您的代码在构建时未使用覆盖率或测试 不在保修范围内(详见下文)。
过时报告 / 延迟时间
绝对覆盖率报告在代码合并后生成,可能需要 需要几个小时才能完全编译。信息中心会显示 已生成报告。如果您在信息中心内没有看到预期结果,请确保 数据是在可能影响到相关的最新更改之后生成的, 覆盖率。如果数据已过时,请稍后返回并刷新页面。
增量覆盖率报告由 CQ 生成。确保您查看的是
发送到 CQ 的补丁集您可以点击“显示实验性 tryjobs”更改为
显示名为 fuchsia-coverage
的 tryjob。如果 tryjob 仍在运行,
请稍后返回并刷新页面。
确保您的测试已运行
如果您的代码未包含您期望的覆盖率,请选择一项测试, 应该已覆盖您的代码,并确保它在覆盖率 tryjob 上运行。
- 在 Gerrit 中查找 tryjob,或者查找
fuchsia-coverage
最近在 CI 信息中心。 - 在“Overview”(概览)标签页中,找到“collect build”(收集 build)然后展开,找到 指向显示不同覆盖率、构建和测试运行 不同的配置
- 每个页面都应有一个“Test Results”标签页,显示 。确保您预期的测试已运行,最好能通过测试。
如果您的测试没有按预期针对任何覆盖率 tryjob 运行,可能有一种原因
只是它仅在 CI/CQ 当前未涵盖的配置中运行。
另一种情况是,测试在覆盖率变体中明确选择不参与。对于
引用您的测试的 BUILD.gn
文件可能如下所示:
fuchsia_test_package("foo_test") {
test_components = [ ":test" ]
deps = [ ":foo" ]
# TODO(https://fxbug.dev/42074368): This test is intentionally disabled on coverage.
if (is_coverage) {
test_specs = {
environments = [
{
dimensions = emu_env.dimensions
tags = [ "disabled" ]
},
]
}
}
}
查找相关背景信息,了解测试在覆盖率方面被禁用的原因,并进行调查。
排查测试未显示覆盖率的情况的示例 (因为未设置为在 CQ 上运行)。请参阅此处。
测试仅在覆盖率上失败或不稳定
与上述内容相关,测试在覆盖率范围内更有可能不稳定 example。因在运行时收集覆盖率而产生的额外开销 拖慢性能,进而影响时间,而时间通常是 以进一步增强稳定性
另一个原因可能是测试期间未在 常规测试运行实验结果表明,测试平均可运行 2.3 倍 因为收集 运行时配置文件。为了适应这一情况,测试运行程序提供了一个更长的 超时。不过,测试 可能会受此影响,设置了各自的内部操作超时。
一般来说,测试不应出现超时。等待时 执行测试中的异步操作,最好无限期等待 测试运行程序的总体超时时间会过期。
最后,在覆盖率上,变体组件可能会使用
fuchsia.debug.DebugData
协议。这会干扰
并准确假设组件使用的功能。查看
实例:
一种立竿见影的解决方法是停用覆盖率测试(请参阅 GN 代码),但无需收集覆盖率信息 。根据最佳做法,您应该对覆盖的不稳定进行相同的处理。 就像您在其他地方处理碎片一样,主要是修复不稳定问题。
另请参阅:不稳定的测试政策。
在 Gerrit 中没有看到预期的覆盖率
如果您发现某些线路没有被覆盖,但确信
这些行应该被正在运行的测试覆盖,请尝试收集覆盖率
再次按下“选择 Tryjobs”,找到fuchsia-coverage
并添加它。
如果 fuchsia-coverage
完成(变为绿色),但您看到的是其他行
则出现以下情况之一:
- 测试以不一致的方式执行被测代码 不同运行。这通常也会导致测试结果不稳定, 出现的问题。
- 覆盖率的生成和收集方式存在问题, 结果不一致。请提交错误。
测试覆盖率的工作原理
Fuchsia 的代码覆盖率构建、测试运行时支持和处理工具使用 基于 LLVM 源代码的代码覆盖率。紫红色 平台受 compile-rt 配置文件运行时支持
当 "coverage"
build 变体处于以下状态时,会启用配置文件插桩
已选择。然后,编译器会生成计数器,每个计数器对应一个
分支,并发出关于分支条目的指令,
递增相关计数器。此外,配置文件插桩
运行时库链接到可执行文件
如需了解实现详情,请参阅 LLVM 代码覆盖映射格式。
请注意,插桩会导致二进制文件大小增加、内存增加 并且测试执行时间会延长我们采取了一些措施来抵消这种情况:
- 配置文件变体中的测试具有更长的超时时间。
- 配置文件变体中的测试在编译时进行了一些优化。
- 目前覆盖率在模拟器上运行,模拟器对存储空间的限制较小。
- 对于增量覆盖率,只有受此项变更影响的来源才会纳入统计范围 插桩。
Fuchsia 上的配置文件运行时库将配置数据存储在 VMO 中,以及
使用 fuchsia.debug.DebugData
向 VMO 发布句柄
协议。此协议可用于在运行时使用
组件框架,由 Test Runner 框架的
设备端控制器测试管理器
系统会在测试领域终止后收集配置文件以及 以及托管在其中的组件这些分析文件随后会处理成一个摘要 进行测试。这是一项重要的优化 总配置文件大小。然后,经过优化的配置文件会发送到主机端测试 控制器。
主机使用 covargs
工具,该工具本身使用
llvm-profdata
和
llvm-cov
工具,用于将原始配置文件转换为摘要
格式,并生成测试覆盖率报告。此外,covargs
会将
将数据转换为 protobuf 格式,该格式用作各种
信息中心
路线图
正在进行的工作:
- 提升了覆盖率运行时的性能和可靠性。
- 对 ZBI 测试的源代码覆盖率的内核支持。
- 自定义覆盖率信息中心和提醒:为您的团队构建信息中心。
- 本地工作流:在本地运行测试,生成覆盖率报告。
- IDE 集成:在 VS Code 中查看覆盖层。
近期作业:
- 树外支持:涵盖 Fuchsia CI/CQ 以外的服务。