RFC-0180:测试界面堆栈

RFC-0180:测试界面堆栈
状态已接受
领域
  • 查看系统
说明

此 RFC 是测试界面堆栈组件的设计方案,该组件将提供特定于界面的测试功能,以测试树内和树外的客户端。

问题
Gerrit 更改
  • 691540
作者
审核人
提交日期(年-月-日)2022-06-16
审核日期(年-月-日)2022-07-26

总结

此 RFC 是测试界面堆栈组件的设计方案,该组件将提供特定于界面的测试功能,以测试树内和树外的客户端。

设计初衷

集成测试对于 Fuchsia 花瓣稳定性至关重要。不过,目前很少有树外(“OOT”)封闭界面集成测试,因为 OOT 客户端在编写此类测试时面临很大障碍。也就是说,他们必须:

  • 了解界面堆栈的深奥含义,通常远远超出其生产用例的范围。
  • 将测试行为与界面堆栈的内部实现细节相结合。
  • 使用仅限内部使用的 FIDL API 运行相关的界面组件。
  • 将测试设计为能够适应界面堆栈中正在进行的各种迁移(GFX -> Flatland、Root Presenter -> 场景管理器、CFv1 -> CFv2)。

测试界面堆栈组件旨在通过代表测试客户端处理低级别界面详细信息来缓解这些问题。

用例示例

  • 客户端运行时的触摸/鼠标/键盘输入测试:对于这些测试,客户端会启动测试界面堆栈,将视图附加到场景,等待视图树状态静止,注入输入,并观察其视图如何处理传入事件。
  • 应用测试:这些测试可以针对界面堆栈运行应用的某一部分,并观察应用如何呈现内容、处理输入以及与无障碍功能的互动等。
  • 界面相邻测试:某些未明确执行界面功能的测试仍可能需要界面存在。例如,针对 fuchsia.web 的测试可能需要测试客户端呈现视图。

利益相关方

谁与此 RFC 被接受是否相关?(本部分为可选内容,但建议阅读。)

教员

leannogasawara@google.com

审核者

  • Fuchsia 测试架构:crjohns@google.com
  • UI + OOT 集成测试:dworsham@google.com、jaeheon@google.com

咨询人员

列出应审核 RFC,但无需审批的人员。

  • 输入:quiche@google.com、neelsa@google.com
  • 无障碍功能:neelsa@google.com、lucasradaelli@google.com
  • 组件框架:yaNeuraly@google.com、geb@google.com、cgonyeo@google.com
  • Flutter:akbiggs@google.com
  • Chromium:sergeyu@google.com
  • Opal:cligh@google.com、anwilson@google.com、robinsontom@google.com

社交

此 RFC 经过了 Fuchsia Testing 和 Fuchsia Input 团队的设计审核。我们还咨询了 OOT 界面客户团队。

术语库

  • 界面堆栈:一组提供基本界面服务的 Fuchsia 组件。大致上,这组包含 Scene、Root Presenter 或 Scene Manager、输入管道、无障碍功能管理器、快捷方式管理器和文本管理器。
  • 测试界面堆栈:我们推荐的组件,用于公开界面堆栈的 Facade(基本界面服务 + 帮助程序服务)。
  • 基本界面服务:从生产界面领域公开的服务集。
  • 帮助程序服务:仅供测试用的服务,可通过更高级别的 API 为客户端代理低级别界面功能。
  • 场景视图的层次结构,可让所有者向显示屏呈现可渲染的内容、使用输入以及与无障碍功能进行交互。

设计

要求

  • 涉及界面的封闭 OOT 集成测试必须易于编写。
  • 涉及界面的封闭式 OOT 集成测试必须易于阅读。
  • 测试功能不得泄露界面堆栈的内部信息。
  • 客户端必须能够配置包含界面堆栈的测试领域。
  • 客户端必须能够扩展测试界面堆栈定义的组件拓扑,以包含测试专用配置。
  • 必须保证对测试进行彻底设置和清理。
  • 各项测试必须相互隔离。
  • 测试界面堆栈不得排除使用 RealmBuilder。
  • 客户必须能够使用自己选择的语言编写测试。

建议

  • 树内和树外界面集成测试应直接类似。

概览

我们提议将一个测试界面堆栈组件添加到 Fuchsia 合作伙伴 SDK 中,该组件将公开生产界面领域的外观。具体而言,此组件将公开以下服务:

  1. 大致上,就是从生产界面领域公开的公共服务集。
  2. 一组仅用于测试的“辅助服务”,通过更高级别的抽象化(例如输入合成、屏幕截图等)提供低级别界面功能。

客户端可以实例化此组件,将所需的界面服务路由到被测组件,向场景呈现视图,并使用提供的各种帮助程序服务来驱动其测试。

替代文本:
显示组件拓扑:
测试管理器 -> 测试固件组件 - 测试固件组件 - 测试固件 - 测试固件 - 测试固件 - 测试固件 - 测试固件 - 测试固件 - 测试固件 - 测试固件 - 测试固件 - 测试固件 - 测试固件 - 测试夹具 - 测试固件 - 测试夹具 - 测试固件 - 测试夹具 - 测试固件 - 测试夹具 - 基本 - 应用堆栈 组件 测试 > 测试固件 组件 - 基本 应用 界面 组件 服务 - 基本 应用 界面 组件 服务 > 测试 软件 吧

请注意,此设计与界面堆栈和测试组件如何配置各自的领域无关。它们可以静态方式或通过 RealmBuilder 来完成此操作。

基本界面拓扑

最初,测试界面堆栈将包含以下基本界面组件,这些组件在撰写时反映了“现代”生产界面堆栈:

  1. 风景优美的,配置为使用平地图。
  2. 场景管理器
  3. 无障碍管理器
  4. 短信管理器
  5. 快捷方式管理器
  6. Cobalt(不是界面组件,但运行场景所需的组件)
  7. 模拟硬件显示控制器(同样,不是界面组件,但场景所需的组件)

此外,测试界面堆栈最初会向测试公开以下基本界面服务:

  1. fuchsia.accessibility.semantics.SemanticsManager
  2. fuchsia.ui.composition.Allocator
  3. fuchsia.ui.composition.Flatland
  4. fuchsia.ui.scenic.Scenic
  5. fuchsia.ui.input.ImeService
  6. fuchsia.ui.input3.Keyboard
  7. fuchsia.ui.input3.KeyEventInjector
  8. fuchsia.ui.shortcut.Manager
  9. fuchsia.ui.shortcut.Registry

请注意,测试界面堆栈可以而且将会不断演变,以镜像正式版界面堆栈。

根据单界面堆栈迁移的进度,我们可能还会添加“旧版”测试界面堆栈组件,它使用 root Presenter 和输入流水线代替场景管理器。

辅助组件

除了上面提到的基本界面组件之外,测试界面堆栈还将包含一组范围较小的帮助程序组件,以便通过较高级别的 API 为客户端提供特定于低级别的界面的功能。在发布时,此数据集可能包括:

  1. 输入合成组件可让客户端将文本、鼠标和触摸输入直接注入输入流水线。
  2. 屏幕截图组件,可让客户端符合人体工学要求截取屏幕截图。
  3. 场景提供程序组件,用于将客户端视图附加到场景,并代表它们注册特权功能(例如作用域几何图形观察者)。请注意,由于场景提供程序会代表客户端注册观察者,因此测试界面堆栈不需要公开任何观察者注册表服务。

测试界面堆栈将公开这些组件的辅助程序服务,客户端可以使用这些服务来驱动测试。

辅助组件抽象具有几项重要优势:

  • 抽象:帮助程序服务会向客户端提供稳定且定义明确的 Facade,这有助于最大限度地减少对界面堆栈内部的依赖。
  • 简洁性:通过专用辅助组件提供的 Vending 界面功能使每个 FIDL API 变得简单而具体,从而改进了用于编写和维护界面测试的 DX。
  • 可扩展性:我们可以通过添加新的帮助程序组件轻松扩展界面 Facade。
  • 与子软件包的兼容性:我们可以转换为子软件包,而且在客户端不会失去功能性。

可配置性

某些客户端可能需要配置参数,例如屏幕旋转角度、像素密度等。测试界面堆栈可以通过结构化组件配置来适应这些用例。客户端可以替换他们想要控制的参数,然后,测试界面堆栈组件可以传播到相应的基本界面组件。

使用示例

下面的伪 C++ 代码段概述了使用测试界面堆栈组件的基本触控输入测试。

// Client test code creates a RealmBuilder instance.
component_testing::RealmBuilder realm_builder;

// Instantiate Test UI Stack component by absolute URL in the test realm.
realm_builder.AddChild("test-ui-stack",
            "fuchsia-pkg://fuchsia.com/test-ui-stack#meta/test-ui-stack.cm");

// Add a test view component to the test realm, and route required UI services
// to it.
realm_builder.AddChild("test-view", ...);
realm_builder.AddRoute({
    .capabilities = {Protocol{fuchsia::ui::scenic::Scenic::Name_}},
    .source = ChildRef{"test-ui-stack"},
    .targets = {"test-view"}},
}});

// Expose fuchsia.ui.app.ViewProvider from the test view.
realm_builder.AddRoute({
    .capabilities = {Protocol{fuchsia::ui::app::ViewProvider::Name_}},
    .source = ChildRef{"test-view"},
    .targets = {ParentRef()}},
}});

// Build the test realm.
RealmRoot realm_root = realm_builder_.Build();

// Connect to the scene provider "helper service", and request to attach a
// test view to the scene.
std::optional<zx_koid_t> client_view_ref_koid;
fuchsia::ui::observation::geometry::Provider geometry_provider;
auto scene_provider = realm_root->Connect<fuchsia::ui::test::scene::Provider>();
auto view_provider = realm_root_->Connect<fuchsia::ui::app::ViewProvider>();
scene_provider->AttachView(std::move(view_provider), geometry_provider.NewRequest(),
  [&client_view_ref_koid](auto view_ref_koid) {
    // Save the client's ViewRef koid.
    client_view_ref_koid = view_ref_koid;
  });

// Wait for client view ref koid to become available.
RunLoopUntil([&client_view_ref_koid] {
  return client_view_ref_koid.has_value();
});

// Use registered geometry provider to wait for client view to render.
ASSERT_TRUE(geometry_provider.is_bound());
geometry_provider.Watch(...);
RunLoopUntil(...);

// Connect to input synthesis helper service, and use to inject input.
auto input_synthesis = realm_root->Connect<fuchsia::ui::test::input::Touch>();
input_synthesis->InjectTap(...);

实现

下面列举的工作流可以并行推进。

工作流:场景提供程序辅助服务

  1. 提交 FIDL 变更。
  2. 实现场景提供程序辅助组件。
  3. 重构现有的树内测试以使用场景提供程序。

此工作流可让测试将视图附加到场景,这对任何图形/输入测试来说都是硬性要求。

工作流:几何图形观察者

  1. 使 fuchsia.ui.observation.geometry 协议在 SDK 中处于 OOT 状态。
  2. 实现“作用域”几何图形观察者注册表。

此工作流允许 OOT 客户端使用与场景图的根无关的几何图形观察者数据,这些数据可能因不同的产品和界面堆栈配置而异。

工作流:输入合成

  1. 重新设计了输入合成 API 以供 OOT 使用。
  2. 向 SDK 添加输入合成 FIDL 库。
  3. 实现 FIDL 库。

此工作流可让 OOT 测试界面堆栈用户注入输入;目前还没有其他替代方法。

工作流:重构树内 UITestManager 库

  1. 将领域配置从现有的内部 UITestManager 类分解为新的 UITestRealm 类,该类可与测试界面堆栈共享。
  2. (可选)实现一种与正式版界面子领域共享 .cml 的机制。如果现在不这样做,我们应该在 One UI Stack 迁移完成后进行此清理。

上述工作流完成后,我们可以在合作伙伴 SDK 中组装测试界面堆栈软件包,并将其添加到供 OOT 客户端运行测试的产品 build 中。

性能

此设计针对已经是多组件的集成测试,因此我们预计所提议的测试拓扑扩展对性能的影响微乎其微。

某些 OOT 测试实际上可能会提升性能,因为它们可以依赖于更稳定的同步模式。

安全注意事项

此 RFC 没有任何安全注意事项。由于测试界面堆栈不使用任何系统功能(sysmem 和 vulkan 除外),因此它无法执行普通的最终用户 Vulkan 程序无法执行的操作。

隐私注意事项

测试界面堆栈无法访问私有资源或敏感资源,因此该 RFC 没有任何隐私权注意事项。

测试

在编写用于使用测试界面堆栈的行为的测试时,我们可以对测试界面堆栈的行为有足够的信心。

文档

我们打算发布一份开发者指南,说明如何使用测试界面堆栈。

缺点、替代方案和未知情况

缺点

在多个客户端之间复制样板

提议的设计为客户提供了一些通用样板可以编写。我们或许可以通过自定义界面专用 fuchsia.test.Suite 实现来消除此痛点,使客户端能够将测试客户端和测试逻辑插入到预定义的界面测试框架中。

已考虑的替代方案

请参阅原始 UI Test Manager RFC