测试范围

影响测试的最常见参数是范围(有时称为“大小”)。

范围是相对于可测试单元而言的。侧重于单个此类单元的测试称为单元测试,同时执行多个单元的测试称为集成测试。大多数测试也可以安排在测试金字塔中。

单元是从测试作者的角度任意定义的。例如,在面向对象的编程中,单元通常是一个类。在本文档中(通常在 Fuchsia 上)经常会提到,除非另有说明,否则受测单元就是一个组件。

在为 Fuchsia 编写测试时,请确保您熟悉有关编写测试的测试原则最佳实践

测试范围

不同范围的测试可以互补各自的优缺点。良好的测试组合可以制定出色的测试计划,让开发者能够自信地做出更改,快速高效地发现真正的 bug。

在考虑要编写的测试类型和每项测试的数量时,不妨将测试想象成一个金字塔结构:

金字塔图示,其中单元测试位于广义群,集成测试位于中部,系统测试位于窄头

许多软件测试出版物都提倡 70% 的单元测试、20% 的集成测试和 10% 的系统测试。Fuchsia 建议,在集成测试方面加大投入,而放弃其他类型的测试,原因如下:

  • Fuchsia 强调软件的组件化。紫红色上的应用和系统倾向于非常广泛地运用组件之间的边界。因此,我们建议您测试这些边界。
  • 借助 Fuchsia 的组件框架,您可以(有时轻松地)在测试中重复使用生产组件,从而降低开发集成测试的成本。
  • Fuchsia 的测试运行时可为集成测试提供与单元测试相同的隔离级别,从而使集成测试变得可靠。
  • 组件之间的通信比直接方法调用慢几个数量级,但仍然非常快。集成测试的运行速度通常不会比单元测试慢到人类开发者能够察觉到的程度。
  • Fuchsia 上已存在许多集成测试,可作为实用示例。

如需详细了解 Fuchsia 中测试金字塔的各项测试,请参阅以下内容:

测试金字塔之外还有一些专门的测试。如需了解详情,请参阅专用测试

另请参见:

单元测试

在 Fuchsia 上,在单个组件中完全定义的测试称为单元测试。

这样可防止测试获取意外功能、受测试范围之外的系统状态影响,以及影响同一设备上并行或依序运行的其他测试。

单元测试由测试正文中的直接代码调用控制。例如,audio_effects_example_tests.cc 在实现音效的可加载模块中练习代码,并验证代码能否正常运行。

在运行状况良好的测试金字塔中,单元测试是广泛的测试基础,因为单元测试提供最高程度的隔离,也是最快的测试,而这反过来又会生成非常可靠且有用的正面信号(测试通过)和负面信号(测试失败,并产生表示真实缺陷的可操作错误)。单元测试还可以生成最实用的测试覆盖率信息,并享受其他附带优势,例如与排错程序结合使用时。因此,任何可通过单元测试满足的测试需求都应通过单元测试来满足。

如果只有测试软件包的内容影响测试是通过还是失败,则可以说单元测试是封闭的。

另请参见:

集成测试

在 Fuchsia 上,涵盖通过单个测试软件包提供的多个组件的测试称为集成测试。

在运行状况良好的测试金字塔中,集成测试是继单元测试之后最常见的测试类型。Fuchsia 上的集成测试通常速度快,但不如单元测试快。Fuchsia 上的集成测试与外部影响与系统的其余部分隔离开来,就像单元测试一样。集成测试的定义和驱动比单元测试更复杂。因此,任何无法通过单元测试满足但可以通过集成测试满足的测试需求都应该通过集成测试来满足。

与其他平台相比,集成测试在 Fuchsia 上发挥着巨大作用。这是因为 Fuchsia 鼓励软件开发者将其代码分解为多个组件,以便实现平台的安全性可更新性目标,然后提供强大的组件间通信机制,例如通道FIDL

在集成测试中 测试由测试领域中的一个组件驱动,该组件也用于确定测试是通过还是失败的,并提供额外的诊断信息。例如,字体服务器集成测试会测试将 fuchsia.pkg.FontResolver FIDL 协议作为协议功能提供的字体解析器组件,然后通过调用与客户端合同中的方法并验证预期的响应和状态转换来验证该组件。

集成测试由测试驱动程序控制。测试驱动程序会设置一个或多个被测组件,对其进行练习,并观察结果,例如使用支持的接口和其他协定查询这些组件的状态。

在测试领域,标准 在测试领域,功能路由通常用作依赖项注入的机制。例如,如果受测组件依赖于测试范围外的另一个组件提供的功能,则可以针对其他组件(“测试替身”)或单独在测试领域内运行的生产组件实例进行测试。

如果只有测试软件包的内容影响测试通过还是失败,则可以说集成测试是封闭的。

另请参见:

  • 复杂的拓扑和集成测试:如何静态定义具有多个组件的测试领域,并在这些组件之间路由功能。
  • Realm 构建器:一个集成测试辅助程序库,用于在运行时构建测试领域并在各个测试用例中模拟组件。

系统测试

在 Fuchsia 上,不限定单个软件包的内容以及其中所含一个或多个组件的内容的测试称为系统测试。此类测试的范围并未严格按照组件或软件包定义,而是可能涵盖并涵盖在给定配置中构建的整个系统。

系统测试有时称为关键用户历程 (CUJ) 测试或端到端 (E2E) 测试。有人可能会认为,如果范围甚至大于单个 Fuchsia 设备(例如,针对远程服务器进行测试,或在存在特定的 Wi-Fi 接入点或其他已连接硬件的情况下进行测试),此类测试可能为 E2E。

在运行状况良好的测试金字塔中,系统测试是金字塔的窄尖,这表示系统测试数少于其他范围内的测试。系统测试通常比单元测试和集成测试慢得多,因为它们需要执行更多代码并具有更多依赖项,其中许多是隐式定义而不是显式声明的。系统测试并不能提供固有的隔离程度,会受更多副作用或意外干扰的影响,因此通常不如其他类型的测试。由于系统测试执行的代码范围是未定义的,Fuchsia 的 CI/CQ 不会从端到端测试中收集测试覆盖率(收集覆盖率会导致结果不稳定或不稳定)。排错程序不支持 E2E 配置。因此,在单元测试或集成测试无法获得边际优势时,您应该编写系统测试。

其他测试

Fuchsia 中有各种专门的测试:

内核测试

由于涉及到独特的要求和约束条件,因此测试内核需要特别注意。内核测试涵盖内核表面:系统调用、内核机制(例如句柄权或信号对象)、vDSO ABI 和用户空间引导,以及任何重要的实现细节。

大多数内核测试在用户空间中运行,并从外部测试内核 API。这些测试称为核心用户模式测试。例如,TimersTest 测试内核的计时器 API。编写这些测试比常规测试更难:仅支持某些编程语言,测试之间的隔离边界较弱,测试无法并行运行,无法在不重新启动和重新启动的情况下更新测试,并且存在其他约束和限制。这些权衡让测试可以减少对其运行时环境的假设,这意味着,即使是在没有组件框架或高级网络功能的最基本的构建配置(启动构建)中,这些测试也可以运行。您可以运行这些测试,防止其他程序在用户模式下运行,这样做有助于隔离内核 bug。

某些内核行为无法从外部测试,因此需要使用能够编译到内核映像并在内核空间中运行的代码对其进行测试。这些测试的编写和问题排查更加困难,但对内核内部组件拥有最多的访问权限,即使在用户空间引导中断时也可以运行。这有时在测试时需要这样做。例如,timer_tests.cc 会测试计时器截止时间,但仅通过从用户空间使用内核 API 无法精确测试这点,因为内核在合并从用户空间设置的计时器方面预留了一些空闲空间

兼容性测试

兼容性测试(有时称为一致性测试)将正确性的概念扩展到符合特定规范并随着时间的推移而符合该规范。兼容性测试以某些合同条款表示,可以针对该合同的多个实现运行,以确保兼容任意数量的实现。

例如:

  • Fuchsia 兼容性测试 (CTF) 是用于验证 Fuchsia 系统接口的测试。CTF 测试可以针对不同版本的紫红色运行,以确保它们保持兼容性或检测破坏性更改。假以时日,CTF 测试将全面覆盖 Fuchsia SDK 的全部功能。
  • FIDL 使用特定的二进制格式(或有线格式)对通过通道在组件之间交换的 FIDL 消息进行编码。FIDL 客户端和服务器端绑定和库支持 C、C++、Rust、Dart 和 Go 等多种语言。FIDL 兼容性测试Golden FIDL (GIDL) 测试可确保不同的实现与二进制文件兼容,以便客户端和服务器无论开发者选择哪种编程语言,都可以正确且一致地相互通信。
  • Fuchsia Inspect 使用特定的二进制格式对诊断信息进行编码。该检查支持多种语言,底层二进制格式可能会随时间而变化检查验证器测试可确保所有读取器/写入器实现之间的二进制文件兼容性。

性能测试

性能测试会执行特定的工作负载(例如合成基准或 CUJ),并在测试期间测量性能指标(例如完成时间或资源使用情况)。

性能测试可以确保满足特定阈值(例如,帧以 60 FPS 的一致速率渲染),也可能直接收集性能信息并将其作为结果呈现。

例如:

  • 您可以在端到端性能测试目录中找到许多性能测试和性能测试实用程序。这些测试涵盖一系列目标,例如内核启动时间、触控输入延迟、Flutter 渲染性能,以及对性能敏感的代码的各种微基准。
  • CPU 性能监控使 CPU 性能计数器可用于高频率低开销性能测试。
  • Perfcompare 是一个框架,用于比较给定更改前后的给定基准结果。它可用于衡量性能提升或回归情况。
  • FIDL 基准针对 FIDL 生成的代码提供了各种大小的基准。
  • Netstack 基准测试使用热代码的微基准测试网络堆栈的性能。

压力和长时测试

压力测试以高负载的方式运行系统,但在系统合同范围内执行。其目标是展示系统对压力的弹性,或者揭示仅在压力下发生的 bug。

在压力测试中,被测系统与测试工作负载组件隔离开来。测试工作负载组件可以执行所希望的任何操作,包括崩溃而不会导致被测系统崩溃。

例如,minfs 压力测试会对 MinFS 分区重复执行许多操作。测试可以验证操作是否成功、是否按预期观察其结果,以及 MinFS 是否不会崩溃或以其他方式出现文件系统损坏等错误。

故意长时间使用某个系统的测试是一种压力测试,称为“长效测试”。在持久性测试中,时间跨度是系统的负载或压力固有的。例如,一个系统成功经历了 10,000 次用户体验历程的测试属于压力测试,而一个系统在循环中经历相同用户体验历程 20 小时并且保持正确且响应速度的测试也属于耐久测试。

另请参见:

模糊测试

模糊测试工具是一些尝试与被测代码进行有效交互的程序,这会导致错误情况,例如崩溃。模糊测试由伪随机行为指导,有时可通过插桩(搜索覆盖新代码路径的输入)或其他明智策略(例如,预先生成的字典或机器学习)指导。

经验表明,模糊测试工具可以找到严重程度较高的独特 bug。例如,reader_fuzzer.cc 在 Inspect 读取器代码中发现了会导致运行时崩溃的 bug,即使此代码已经过广泛的测试和排错程序。

另请参见: