Fuchsia 可测试性评分准则

目标

本文档的目标

Fuchsia 可测试性是一种可读性形式,侧重于确保对 Fuchsia 的更改引入可测试和测试的代码。

与任何可读性流程一样,准则和标准最好公开发布,供审核者和审核者查看。本文档是与编程语言可读性流程样式指南等效的 Fuchsia 可测试性。

始终如一地应用可测试性标准很重要,因此,参与可测试性的所有人员都应该研究文档(无论您是在审核更改还是编写更改),这一点非常重要。

文档的确切内容可能会随时间而变化。

您作为可测试性审核人员的目标

  • 确定是否测试更改。如果您同意测试已通过测试,请应用Code-Review+2;如果未测试,请回复备注,说明缺失的信息。
  • 一致地应用标准(本文档)。
  • 如果需要修改更改以符合标准,请提供切实可行的反馈。
  • 推广 Fuchsia 测试和可测试性。
  • 找出本文档未处理的案例,并提出更改建议。
  • 遵循标准,但也要谨慎判断。目标是提高质量并促进一种测试文化。您不需要执行精确的决策算法。

您作为变更创建者的目标

  • 请阅读本文档(您正在做的就是!),了解这些标准。
  • 请尊重可测试性审核人员自愿为此角色提供协助,并妥善对待他们。
  • 考虑用户提供反馈,了解如何通过测试提高对更改的信心。

测试内容如何测试?

  • 功能更改应包含在不更改内容的情况下就会失败的测试。
  • 测试必须位于要更改的代码的本地位置:具有测试覆盖范围的依赖项不计入测试覆盖率。例如,如果“B”使用“A”,并且“B”包含测试,则无法涵盖“A”。如果通过“B”的测试发现 bug,它们将会间接出现,因此更难确定为“A”。同样,如果“B”已废弃(或仅更改其依赖项),“A”的所有覆盖范围都将丢失。
  • 测试必须自动执行(如果支持 CI/CQ)。手动测试是不够的,因为无法保证将来对代码所做的更改(尤其是由另一位工程师编写的代码)也会执行相同的手动测试。代码库的某些部分可能属于例外情况,以识别持续存在的自动化挑战。
  • 测试必须尽量减少其外部依赖项。我们的测试基础架构会为每项测试明确配置特定的资源,但测试所能访问的资源远不止所预配的资源。资源示例包括硬件、CPU、内存、永久性存储空间、网络、其他 IO 设备、预留网络端口和系统服务。我们无法保证未为测试明确预配的资源的稳定性和可用性,因此访问此类资源的测试本身就会不稳定且 / 或难以重现。测试不得访问超出测试基础架构控制范围的外部资源。例如,测试不得访问互联网上的服务。仅在必要时,测试应使用为该测试明确预配的资源。例如,测试可能必须访问没有测试替身可用的系统服务。此规则的少数例外情况适用于端到端测试。
  • 对旧版代码的更改(即早于可测试性要求的旧代码,且未经过充分测试的旧代码)必须进行测试。靠近测试不佳的代码不是不测试新代码的理由。未经测试的旧代码并不一定是老旧内容,可能是经过验证且经过实战强化的,而未经测试的新代码更有可能失败!
  • 您对他人代码所做的更改需遵循相同的可测试性要求。如果作者要更改代码,而他们不熟悉或不负责更改代码,则更有必要对其进行良好测试。作者需要与相关负责人或团队合作,以找到测试更改的有效方法。负责更改中的代码的人员应帮助作者实现可测试性,并且其优先级与作者更改的优先级相同。

不需要测试的内容

缺少以下各项的测试覆盖范围应该不会阻止更改收到 Code-Review+2

  • 日志记录。在大多数情况下,可能不值得测试组件的日志输出。系统的其余部分通常将日志输出视为不透明数据,这意味着对日志输出的更改不太可能破坏其他系统。但是,如果日志输出在某种程度上承受负载(例如,某个其他系统可能依赖于观察某些日志消息),则应该对该协定进行测试。这也适用于其他形式的插桩,例如跟踪。这不适用于以协定形式使用的插桩。例如,可以对 Inspect 的使用进行测试;如果您依赖插桩测试(例如在 ffx inspect 或反馈报告中),就应该采用这种方式。
  • 我们不拥有的代码(可信来源不在 Fuchsia 树中)。 如果更改包含从其他位置复制的源代码的更新,则无需满足可测试性要求。
  • 完全重构(可能完全由自动重构工具完成的更改)不符合可测试性要求,例如移动文件、重命名符号或删除符号。某些语言可能会采用发生此类更改的行为(例如运行时反射),因此可能会出现例外情况。
  • 生成的代码。由工具生成的更改(例如格式设置,或作为黄金文件签入的生成代码)不具有可测试性要求。顺便提一句,我们通常不建议签入生成的代码(而不是利用工具并在构建时生成代码),但在特殊情况下,不需要对机器编写的代码进行测试。
  • 可测试性引导。如果更改是为向代码引入可测试性做好准备,并且作者对此进行了明确说明,则可测试性审核人员可以自行决定并采用 IOU。
  • 手动测试。手动测试本身通常用于测试或演示难以以自动化方式测试的功能。因此,对手动测试进行添加或修改不需要自动化测试。不过,强烈建议您将手动测试与描述如何运行这些测试的 README.mdTESTING.md 文档搭配使用。
  • 硬编码值。添加或更改硬编码值不一定需要测试。通常,这些值用于控制不易观察的行为,例如未公开的实现细节、启发式方法或“外观”更改(例如界面的背景颜色)。对样式 assert_eq!(CONFIG_PARAM, 5); 的测试不被认为有用,并且不是可测试性所必需的。但是,如果贡献内容会导致易于观察到的行为变化,那么该贡献应包含针对新行为的测试。

哪些情况需要测试

如要修复不稳定的情况,请在 CQ 中测试不稳定性

如果修复不稳定,请通过测试 CQ 中的不稳定来验证修复。

测试不应休眠

休眠可能会导致测试不稳定,因为在不同测试环境中难以控制时间。造成这种困难的因素包括测试目标的 CPU 速率、核心数量、系统负载以及温度等环境因素。

  • 避免如下情况:

    // Check if the callback was called.
    zx_nanosleep(zx_deadline_after(ZX_MSEC(100)));
    EXPECT_EQ(true, callback_happened);
    
  • 而是明确等待条件:

    // In callback
    callback() {
        sync_completion_signal(&event_);
    }
    
    // In test
    sync_completion_wait(&event_, ZX_TIME_INFINITE);
    sync_completion_reset(&event_);
    

    此代码示例根据 task_test.cc 改编而来。

针对竞态条件的回归测试

很难针对错误通过率不高的竞态条件编写回归测试。如果您能够编写一个确定能够重现问题的测试,则应该这样做。如需了解相关提示,请参阅编写可重现的确定性测试。否则,如果通过改进使用的锁定方案解决了数据争用问题,您可以添加线程注解作为回归测试。对于其他竞态,您应尝试设计 API 来防止出现竞态条件。

最近移除的豁免情况

  • Engprod 脚本(例如 fx 命令)和关联的配置文件不再免于可测试。fx 必须进行集成测试,才能发布进一步的更改。在咨询可测试性审核人员后,fx 团队可能会授予例外情况。

临时可测试性豁免

以下项目前无需进行可测试性测试,而正在进行的工作旨在改变这一点。

  • tools/devshell/contrib 和关联配置中的 Engprod 脚本除外。
  • GN 模板不易测试。我们正在开发适用于 GN 模板的测试框架在此之前,只能对 build 模板更改进行手动测试。
  • 在 C 样式的代码中,资源泄漏很难预防。从长远来看,应重构此类代码,以使用 Rust 或现代 C++ 习惯用法,以降低泄露的可能性,并且应存在能够自动检测泄露的自动化。
  • Gigaboot//src/firmware/gigaboot 中早于可测试性政策的 UEFI 引导加载程序。目前,还没有可用于为 UEFI 代码编写集成测试的基础架构。您可以在 https://fxbug.dev/42109789 中跟踪该基础架构的介绍。在 https://fxbug.dev/42109789 得到解决之前,将授予可测试性例外情况。