- 跨平台
- UI组件
- 桌面应用
【免费下载链接】toga
A Python native, OS native GUI toolkit.
本篇指南面向想要为 Toga(Python 原生、操作系统原生 GUI 工具包)贡献代码的开发者,系统讲解从搭建开发环境、创建分支,到运行toga-core与 Travertino 测试套件、驱动跨平台 Testbed 应用进行真实 GUI 验证,直至提交 Pull Request 的完整流程。读完本文,你将掌握tox标签化测试命令、Briefcase 开发者测试模式、slow mode 等核心工具,并理解测试覆盖率为 100% 这一项目硬性要求背后的实现机制。
开始之前:开发环境与分支约定
动手写代码之前,请先确认两件事:
- 开发环境已就绪:参考 dev-environment.md 完成环境搭建。不同平台需要安装对应的原生 GUI 依赖——macOS 需要 macOS 前置依赖,Linux 需要 GTK 或 Qt 开发依赖,Windows 需要 Windows 前置依赖,并执行类似
python -m pip install -e ./core -e ./dummy -e ./cocoa -e ./travertino --group dev(平台不同,后端包不同)的 editable 安装。 - 工作分支已创建:Toga 明确要求从 feature 分支工作,而不是直接在
main分支上开发,具体约定见 branches.md。
完成上述准备后,你才能进入代码的编写、运行与测试环节。
测试套件全景:两条测试主线
Toga 仓库的测试体系分为两条主线:
- 核心库(toga-core):即
core/目录下的toga包,测试位于 core/tests,覆盖 app、window、widgets、command、sources、style 等全部核心 API; - Travertino:
travertino/目录下的独立包,定义了核心库所依赖的底层布局机制与样式定义(layout 与 style),测试位于 travertino/tests。
这两条测试主线由仓库根目录 tox.ini 统一编排。tox.ini 中通过labels定义了一组语义化的测试入口:
labels = test = py-cov{,-trav},coverage{,-trav} test-core = py-cov,coverage test-trav = py-cov-trav,coverage-trav也就是说,test-core会运行核心测试并在最后输出覆盖率报告;test-trav对应 Travertino;test则两者都跑,依次输出两份覆盖率结果。这些标签正是下文所有tox -m ...命令的入口。
运行完整测试套件
只测核心库(toga-core)
在项目根目录((.venv)虚拟环境中)执行:
(.venv) $ tox -m test-core该命令对应test-core = py-cov,coverage标签:先以coverage run方式执行 pytest,再合并并输出覆盖率报告。与完整测试套件一致,核心库测试应报告100% 测试覆盖率。tox 环境中还通过TOGA_BACKEND = toga_dummy指定了toga_dummy作为测试后端(见 tox.ini),所有核心测试均在无头(dummy)后端上运行,不依赖任何真实 GUI 环境。
只测 Travertino
(.venv) $ tox -m test-trav与核心库一样,Travertino 的测试也应报告100% 测试覆盖率。执行时 tox 会将工作目录切换到travertino(tox.ini 中changedir = travertino),并仅安装 Travertino 及其测试依赖。
同时测试核心与 Travertino
(.venv) $ tox -m test这会依次运行两套测试,并在最后先后输出两份覆盖率结果(核心一份、Travertino 一份),两者同样都应达到 100%。
只运行某个测试子集
当你只需要针对某个特定文件或用例做快速迭代时,不必跑完整套件。核心库的 pytest 参数可以直接透传给py-cov环境,例如只运行test_command.py:
(.venv) $ tox -e py-cov -- tests/command/test_command.py而如果目标是 Travertino 的某个测试,则在环境名后追加-trav,并把测试路径换成 Travertino 的tests目录:
(.venv) $ tox -e py-trav -- tests/path_to_test_file/test_some_test.py--之后的所有参数都会原样透传给 pytest,所以你可以继续追加-k、-x、--pdb等 pytest 原生选项。需要说明的是,直接运行 pytest 子集时不会生成覆盖率报告,覆盖率仍由coverage环境在完整运行后汇总产出。
Testbed:验证真实后端行为的 GUI 测试应用
上述tox套件只覆盖了toga-core与travertino——它们都在 dummy 后端上运行,不涉及真实 GUI。那么各平台后端(Cocoa、WinForms、GTK、Qt、Android、iOS、Web、Textual)的行为如何验证?答案就是Testbed 应用。
Testbed 的工作原理
Testbed 的核心思路是:用核心 API 编写一套通用的行为测试,再通过"探针"(probe)机制去操作和检查真实后端内部状态。详细设计见 testbed.md:
- 通用行为测试位于 testbed/tests,它们通过控件的公开 API触发各种边界情况,并在一个真实运行的 App 事件循环上以
async方式执行; - 每个后端在自己的
tests_backend目录中实现 probe(如 cocoa/tests_backend、android/tests_backend)。probe 能访问公开 API 无法触及的内部状态——例如控件的物理尺寸、渲染所用的字体,还能模拟点击等 GUI 事件来验证回调是否正确触发; - probe 提供
redraw()方法:GUI 框架常将视觉变更批量合并到一次重绘中,测试在断言属性前调用await probe.redraw()可确保所有待处理的重绘事件已被处理; - 当某个平台尚未实现某控件/方法时,测试或 probe 应调用
pytest.skip()(conftest.py 提供了skip_on_platforms()、skip_on_backends()等辅助函数);若该平台永不支持某特性,则用pytest.xfail()标记预期失败。
Testbed 的运行逻辑集中在 testbed/tests/testbed.py:它负责选择后端、启动 coverage 跟踪(含针对 Wayland/X11、GTK3/GTK4/libadwaita、.NET Framework/Core 等环境的条件覆盖规则)、解析--slow/--coverage/--ci参数,并在 App 主循环中通过后台线程执行 pytest。值得一提的还有toga_dummy之外的后端选择逻辑:TOGA_BACKEND环境变量优先,否则按sys.platform自动映射(darwin→toga_cocoa、linux→toga_gtk、win32→toga_winforms等)。
运行 Testbed 应用(桌面平台)
运行 Testbed 需要 Python 3.12 虚拟环境并安装 Briefcase)。注意:虚拟环境中应只安装一个后端——即你打算测试的那一个。
macOS 下运行(默认使用 Cocoa 后端):
(.venv) $ python -m pip install briefcase (.venv) $ cd testbed (.venv) $ briefcase dev --app testbed --testLinux 下需要显式指定后端。测试 GTK3 后端:
(.venv) $ python -m pip install briefcase (.venv) $ cd testbed (.venv) $ TOGA_BACKEND=toga_gtk briefcase dev --app testbed --test测试 GTK4 后端(不使用 libadwaita):
(.venv) $ python -m pip install briefcase (.venv) $ cd testbed (.venv) $ TOGA_BACKEND=toga_gtk TOGA_GTK=4 TOGA_GTKLIB=None briefcase dev --app testbed --test测试 GTK4 后端(使用 libadwaita):
(.venv) $ python -m pip install briefcase (.venv) $ cd testbed (.venv) $ TOGA_BACKEND=toga_gtk TOGA_GTK=4 TOGA_GTKLIB=Adw briefcase dev --app testbed --test测试 Qt 后端(注意 app 名不同,为testbed-qt,其 Briefcase 配置定义在 testbed/pyproject.toml 的testbed-qt小节):
(.venv) $ python -m pip install briefcase (.venv) $ cd testbed (.venv) $ TOGA_BACKEND=toga_qt briefcase dev --app testbed-qt --testWindows 下(默认 WinForms 后端):
(.venv) C:\...>python -m pip install briefcase (.venv) C:\...>cd testbed (.venv) C:\...>briefcase dev --app testbed --test执行后会出现一个 Toga 应用窗口,它会在执行全部 GUI 测试的过程中不断闪烁,最终在测试全部通过后输出一份已执行代码的覆盖率报告(testbed 同样追求 100% 覆盖率,未覆盖会令返回码非零,见 testbed.py)。
重要提醒:测试期间请远离键盘和鼠标!Testbed 通过真实触发鼠标点击、并检查控件与窗口焦点变化来断言行为,因此必须全程独占输入控制权,测试过程中任何人工输入都会干扰结果。
关于 Python 版本:虽然 Toga 本身支持从最低 Python 版本起的所有版本,但 Testbed 只支持 Python 3.12。这是有意为之的简化——跨 Python 版本的行为一致性由核心测试保证,Testbed 只需验证核心 API 在各平台后端上的表现一致即可。
关于 GTK4 与 Qt:这两个后端目前仍是实验性且仅部分实现的状态,因此运行时会跳过大量测试。补齐这些缺失控件的实现,正是非常受欢迎的贡献方向。
运行 Testbed 子集与 slow mode
Testbed 完整套件运行较慢,你可以用与主测试套件相同的方式透传 pytest 参数来只跑子集。此外 Testbed 还有一个核心测试没有的独特功能——slow mode:它会以同样的顺序执行测试,但在每个 GUI 动作之间刻意暂停 1 秒,方便你亲眼观察测试过程。slow mode 通过--slow启用,而 1 秒延迟正是借由每个redraw()请求实现的(见 testbed.md)。
例如,只以 slow mode 运行 Button 控件的测试:
(.venv) $ briefcase dev --app testbed --test -- tests/widgets/test_button.py --slowLinux 下 Qt 后端对应:
(.venv) $ briefcase dev --app testbed-qt --test -- tests/widgets/test_button.py --slow这类测试会耗时明显更长,但你能在屏幕上看到 Button 控件依次经历各种颜色、格式与尺寸变化。注意:运行测试子集或启用 slow mode 时不会输出覆盖率报告。
运行 Testbed 测试(移动平台)
briefcase dev开发者模式只适用于桌面平台(Cocoa、WinForms、GTK)。要测试移动后端,必须改用briefcase run,将应用部署到模拟器或设备上执行。
macOS 下:
(.venv) $ briefcase run android --app testbed --test (.venv) $ briefcase run iOS --app testbed --testLinux 下只能运行 Android 套件(iOS 测试无法在 Linux 上执行):
(.venv) $ briefcase run android --app testbed --testWindows 下同样只能运行 Android 套件(iOS 测试无法在 Windows 上执行):
(.venv) C:\...>briefcase run android --app testbed --testbriefcase run同样支持--slow与 pytest 参数透传,语法与开发者模式一致(--之后追加参数)。移动端测试会依赖 testbed/pyproject.toml 中声明的相机、定位等权限(permission.camera、permission.fine_location等),并在 Android 构建中通过build_gradle_extra_content配置了 pytest 断言重写与覆盖率所需的源文件提取。
测试完成之后:提交 Pull Request
当一切就绪,就可以把你的改动提交为 Pull Request,详见 submit-pr.md。提交 PR 通常还需要附带一条 change note(放在changes/目录下的新文件里),经 PR 评审流程 通过后才能合入。
关键源码与配置索引
| 关注点 | 仓库路径 |
|---|---|
| tox 标签与测试环境定义 | tox.ini |
| 核心测试套件 | core/tests |
| 核心 pytest/覆盖率配置 | core/pyproject.toml |
| Travertino 测试套件 | travertino/tests |
| Testbed 运行逻辑 | testbed/tests/testbed.py |
| Testbed 测试辅助与 skip/xfail 工具 | testbed/tests/conftest.py |
| Testbed 控件测试示例 | testbed/tests/widgets/test_button.py |
| Testbed Briefcase 清单 | testbed/pyproject.toml |
| Testbed 工作原理专题 | docs/en/topics/internal/testbed.md |
- 跨平台
- UI组件
- 桌面应用
【免费下载链接】toga
A Python native, OS native GUI toolkit.
相关推荐
UltiSnips 贡献指南:从测试编写、代码规范到 Bug 复现的完整开发工作流
UltiSnips 贡献指南:从测试编写、代码规范到 Bug 复现的完整开发工作流 UltiSnips 是 Vim/Neovim 生态中功能最深的代码片段(sn
开发工具Codon 贡献指南:开发工作流、编码规范与测试编写实战
Codon 贡献指南:开发工作流、编码规范与测试编写实战 本文是 Codon 编译器项目(A high performance, zero overhead,
编译器编程语言语言运行时scrcpy 投屏:三步搞定安卓屏幕镜像、录屏与远程操控
scrcpy 投屏:三步搞定安卓屏幕镜像、录屏与远程操控 想把手机内容搬到大屏,又不想在手机上装任何 App、不碰 Root?scrcpy 投屏就是干这个的:免
音视频
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考