Microsoft 发布了一份使用 MSTest 和 Microsoft.Testing.Platform 测试 UWP 与 WinUI 3 应用的实用指南,统一了不同运行模型下的测试生命周期,包括 MSIX 格式的已打包应用、未打包应用,以及在 AppContainer 中运行的应用。该材料由首席软件工程师 Amaury Levé 撰写,重点关注决定测试主机运行方式的细节,而不是界面测试本身的编写。
选择运行模型
Microsoft 区分了打包方式与信任级别。打包会增加 MSIX 身份和 AUMID 激活方式,而信任级别决定进程是以完整权限运行,还是在 AppContainer 内运行。材料建议,在不需要包身份、已打包的激活契约或匹配已安装应用行为时,先从未打包的 WinUI 3 应用开始。UWP 则天然仍与打包和 AppContainer 环境相关联。
对于未打包应用,Microsoft.Testing.Platform 使用直接通过 apphost 启动的路径;而已打包应用需要注册包布局并通过 AUMID 激活。配置为在 AppContainer 内运行的 WinUI 3 应用还需要精确委托对控制台通信通道、取消操作、TRX 文件、HangDump 和重试机制的访问权限;Microsoft 警告不要改为授予 ALL APPLICATION PACKAGES 权限。
设置 MSTest 和 Microsoft.Testing.Platform
Microsoft 建议安装 MSTest.Sdk 4.5,并在 global.json 文件中选择 Microsoft.Testing.Platform,以便 dotnet test 在 .NET 10 中使用原生测试平台,而不是 VSTest。MSTest.Sdk 4.5 包含 MTP 2.5、面向应用模型的侧载控制台、所需的 UWP 资产,以及已打包应用运行器。
在现代 UWP 中,设置要求使用 UseUwp 和 PublishAot,并配合适当的 Windows 目标框架。应用必须在 OnLaunched 内使用 PackagedAppExtensions.GetTestApplicationArguments,将激活参数传递给生成的辅助程序 MicrosoftTestingPlatformApplication.RunAsync。传统 UWP 项目则保留现有结构,在 MSBuild.Sdk.Extras 之外导入 MSTest.Sdk,然后通过 Developer PowerShell 中的 InvokeTestingPlatform 目标运行测试。
WinUI 3 主机和 UI 调度器
材料建议构建一个自托管的 WinUI 3 测试应用,由应用创建窗口并拥有入口点,然后在同一进程内运行 MSTest。窗口激活后,应用将 DispatcherQueue 对象发布到 UITestMethodAttribute.DispatcherQueue,随后调用 RunAsync。必须将 Environment.ExitCode 设置为测试运行结果,因为 WinUI 创建的入口点返回 void;忽略这一点可能导致构建系统或 CI 将失败的运行显示为成功。
示例说明,UITestMethod 会将完整测试(包括 TestInitialize 和 TestCleanup)传递给 WinUI 调度器。而 STATestMethod 会提供 STA 线程,但不会自行创建 WinUI 调度器,因此对于依赖 DispatcherQueue 的界面测试,仅使用它是不够的。
实际会发生什么变化?
这种方法的核心价值在于,在 UWP 与 WinUI 3 之间,或在已打包与未打包运行之间切换时,可以保留相同的 MSTest 和测试生命周期,只需更改部署设置和启动路径。在未打包的 WinUI 3 中,将 WindowsPackageType 设置为 None,并禁用 MSIX tooling。已打包运行则保留 Package.appxmanifest 清单和包资产,并要求 Windows TFM 为 10.0.19041.0 或更高版本,以及允许侧载安装的策略,例如 Developer Mode。
在 .NET 10 中,两种模型都可以通过 dotnet run 或 dotnet test --project 运行;而 AppContainer 内的 UWP 和 WinUI 3 测试则通过自定义 MSBuild 目标,并从未提升权限的 Developer PowerShell 中运行。Microsoft 警告不要将 dotnet exec 与未打包应用结合使用,因为将 dotnet.exe 加入运行路径可能导致 WinUI 资源加载问题。
在 CI 中进行验证
构建成功并不足以确认已打包测试有效。应检查实际 CI 代理映像、注册包的用户上下文、Developer Mode 或侧载安装策略,以及包声明的框架。预先安装了 Windows App SDK 或 UWP 包的开发者设备可能会掩盖只有在干净代理上才会出现的差距。依赖 Windows App SDK 框架的应用还需要匹配的运行时版本,除非以 self-contained 形式构建;即使在这种情况下,也必须测试将在 CI 中使用的同一包模型。