使用Microsoft。Testing.Platform (MTP)在 WinUI 3 应用中运行 MSTest 测试。 WinUI 应用充当测试主机。 它拥有应用程序入口点、UI 线程和进程生存期。
在两个 WinUI 3 部署模型之间进行选择:
- 未打包的应用作为常规Windows可执行文件运行。
-
打包的完全信任应用保留 MSIX 包标识,并使用实验
Microsoft.Testing.Extensions.PackagedApp扩展注册和激活测试主机。
Important
packaged-app 扩展支持完全信任打包的桌面应用。 它不支持 UWP 或其他 AppContainer 测试主机。
打包的完全信任 AUMID 激活在存储库中 microsoft/testfx 实现,但截至 2026 年 8 月 6 日,公共 NuGet 包中不可用。 当前1.0.0-alpha包不包含特定于Windows的激活实现。 仅在包发布标识对完全信任 MSIX 注册和 AUMID 激活的支持后,才使用打包安装程序。
选择部署模型
在配置测试项目之前选择部署模型。
| 要求 | 选择 | 测试主机启动 |
|---|---|---|
| 测试不需要包标识或需要包标识的 API。 | 未包装的 | MTP 直接启动应用可执行文件。 |
| 测试需要 MSIX 包标识或打包应用行为。 | MTP 预览版公开发布后打包的完全信任 | 打包的应用扩展注册生成输出,并通过应用程序用户模型 ID(AUMID)激活应用。 |
| 测试必须在 UWP 或其他 AppContainer 中运行。 | VSTest | MTP 打包应用扩展不支持 AppContainer 隔离。 |
除非测试需要包标识,否则请使用未打包的应用。 未打包的模型不需要包注册、开发人员模式或实验性打包应用扩展。
在公共 MTP 预览版包括完全信任的 MSIX 注册和 AUMID 激活之前,请使用 VSTest 进行打包的完全信任 WinUI 3 测试。
了解 UWP 边界
不要将 UWP 视为另一个打包的 WinUI 3 模型。 面向 UAP 10 和新式.NET UWP 项目的经典 UWP 项目都设置为UseUwptrue在 AppContainer 中运行。 打包 WinUI 3 桌面应用不会将其置于该应用模型中。
将 VSTest 用于经典 UWP 和新式 .NET UWP 测试。 MTP 打包应用启动器面向完全信任打包的桌面主机。 它无法将其激活参数或控制器连接传送到 AppContainer 主机。
有关新式 .NET UWP 配置,请参阅 MSTest .NET 9 UWP 示例。
配置 WinUI 测试主机
这两种部署模型使用相同的自承载 MTP 设置。
设置通用项目属性
在 WinUI 测试项目中设置这些属性:
<OutputType>Exe</OutputType>
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
<UseWinUI>true</UseWinUI>
<EnableMSTestRunner>true</EnableMSTestRunner>
<GenerateTestingPlatformEntryPoint>false</GenerateTestingPlatformEntryPoint>
使用 .NET 8 或更高版本支持.NET版本。 该示例面向Windows平台版本10.0.19041.0。 打包的应用扩展需要此版本或更高版本。
保留指向测试应用的 XAML 文件的 WinUI ApplicationDefinition 项。 WinUI 从该项生成入口点。 若要防止 MTP 生成第二个入口点,请设置为 GenerateTestingPlatformEntryPointfalse。
添加对当前兼容版本的 MSTest 和Microsoft的包引用。WindowsAppSDK。
从应用程序托管 MTP
WinUI Application 类中的重写OnLaunched。 创建并激活测试窗口,然后发布其调度程序队列:
_window = new UnitTestAppWindow();
_window.Activate();
UITestMethodAttribute.DispatcherQueue = _window.DispatcherQueue;
添加 using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer; 。UITestMethodAttribute
从命令行参数创建 MTP 应用程序。 然后注册 MSBuild 贡献的扩展:
string[] cliArgs = Environment.GetCommandLineArgs().Skip(1)
.Where(arg => !arg.Contains("EnableMSTestRunner")).ToArray();
ITestApplicationBuilder builder = await TestApplication.CreateBuilderAsync(cliArgs);
builder.AddSelfRegisteredExtensions(cliArgs);
using ITestApplication app = await builder.BuildAsync();
为 MTP 生成器类型添加 using Microsoft.Testing.Platform.Builder; 。 WinUI 生成将添加到 EnableMSTestRunner 进程参数中。 由于它不是 MTP 命令行选项,因此请在创建测试应用程序之前将其删除。
项目禁用生成的 MTP 入口点,因此调用 AddSelfRegisteredExtensions。 对于打包的应用,该方法还会注册 Microsoft.Testing.Extensions.PackagedApp 启动器。
在 OnLaunched块中,将测试应用程序创建和执行放在一个 try 块中。 将结果await app.RunAsync()Environment.ExitCode分配给 。
finally在块中,关闭窗口并调用应用程序Exit的方法。
生命周期步骤提供两个保证:
- 进程返回 MTP 退出代码,因此失败的测试将生成非零进程退出代码。
- WinUI 消息循环在运行后停止,而不是使测试进程保持活动状态。
Warning
不要添加到 [assembly: WinUITestTarget(...)] 自承载 WinUI 测试应用。 该属性为单独的测试主机启动 WinUI 应用程序。 自承载应用首先调用 Application.Start 。 然后,该属性会尝试在同一进程中启动第二个应用程序。
有关完整实现,请参阅 未打包的 WinUI 示例 和 打包的 WinUI 示例。
在 UI 线程上运行测试
用于 UITestMethod 创建或访问 WinUI 对象的测试。 MSTest 在分配的调度程序队列上 OnLaunched计划测试。
[UITestMethod]
public void CreatesControlOnUiThread()
{
var grid = new Grid();
Assert.IsTrue(grid.DispatcherQueue.HasThreadAccess);
}
常规 TestMethod 程序不会在 WinUI 调度程序队列上运行。 将其用于不需要 UI 线程的测试。
配置未打包的测试应用
对于未打包的应用,请添加以下属性:
<WindowsPackageType>None</WindowsPackageType>
<EnableMsixTooling>false</EnableMsixTooling>
不要引用 Microsoft.Testing.Extensions.PackagedApp。 未打包的应用没有 MSIX 标识或其 AppxManifest.xml 输出,因此 MTP 可以直接启动其可执行文件。
默认情况下,当项目满足以下条件时,Windows 应用 SDK注入其启动初始值设定项:
-
WindowsPackageType是None。 -
OutputType是Exe或WinExe。 -
WindowsAppSDKSelfContained不是true。
如果不是Windows 应用 SDK应用的主机加载测试库,请在库中设置为WindowsAppSdkBootstrapInitializetrue。
注释
VSTest 不支持此未打包的 WinUI 配置。 使用 MTP 运行项目。
配置打包的完全信任测试应用
保留默认打包的 WinUI 配置:
- 不要将
WindowsPackageType设置为None. - 保留
Package.appxmanifest项目中的包资产。 - 设置为
EnableMsixToolingtrue项目是否使用单项目 MSIX 打包工具。
在包含完全信任的 MSIX 注册和 AUMID 激活的预览版可用后,请添加该特定版本的Microsoft。Testing.Extensions.PackagedApp 包。 请勿将早期 1.0.0-alpha 包用于此设置。
包的 MSBuild 属性通过 AddSelfRegisteredExtensions.. 不要也调用 AddPackagedAppDeployment。 MTP 运行只能注册一个测试主机启动器。
启动器执行以下操作:
- 它会检查描述测试可执行文件的一个
AppxManifest.xml。 - 它将生成输出布局注册到 Windows。
- 它从已注册的包和清单应用程序 ID 解析应用的 AUMID。
- 它通过 AUMID 激活应用,并将激活的进程连接到 MTP 控制器。
除非测试可执行文件的入口点,否则启动器将忽略上级目录中 Application 不相关的清单。 引用包的未打包应用间接保留在直接启动路径上。
在运行打包的测试应用之前,请满足以下要求:
- 将特定于Windows的目标框架与平台版本
10.0.19041.0或更高版本配合使用。 - 若要注册未签名的生成输出布局,请启用开发人员模式或配置旁加载。
- 使用完全信任的打包桌面应用。 该扩展不支持 UWP 或其他 AppContainer 主机。
Caution
Microsoft.Testing.Extensions.PackagedApp 扩展点是实验性的 ITestHostLauncher 。 将来的版本可能会更改或删除其 API 和行为。 在生产测试基础结构中使用打包模型之前评估风险。
运行测试
从包含 WinUI 测试项目的目录中,运行:
dotnet run
若要指定项目,请使用 dotnet run --project .\WinUITests.csproj。
对于未打包的应用,MTP 直接启动可执行文件。 对于打包的应用,打包的应用启动器会注册布局,并通过 AUMID 激活应用。
在这两个模型中,测试窗口打开,MTP 运行测试,窗口关闭。 然后,终端报告测试摘要。 成功的运行会退出并包含代码 0。 测试失败时, OnLaunched 将非零 RunAsync 结果 Environment.ExitCode分配给 。
用于 dotnet run 任一模型。 若要直接运行未打包的应用,请使用生成的应用可执行文件。 请勿使用 dotnet exec ,因为 WinUI 会相对于进程路径解析 PRI 资源。
设置疑难解答
使用这些检查来检查最常见的安装失败:
| 症状 | 检查 |
|---|---|
应用报告对 . 的 Application.Start多次调用。 |
WinUITestTarget从自承载测试应用中删除该属性。 |
| 测试运行已完成,但进程保持打开状态。 | 关闭测试窗口,并在之后RunAsync调用Exit块finally。 |
失败的测试仍返回进程退出代码 0。 |
将结果RunAsyncEnvironment.ExitCode分配给 。 |
未打包的运行失败,因为 AppxManifest.xml 缺少。 |
确认项目启用 MTP,并且运行不使用 VSTest。 |
| 打包的运行无法注册或激活应用。 | 确认特定于Windows的目标框架、开发人员模式或旁加载配置、完全信任的应用模型和清单可执行文件条目。 |