使用 MSTest 和Microsoft测试 WinUI 3 应用。Testing.Platform

使用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注入其启动初始值设定项:

  • WindowsPackageTypeNone
  • OutputTypeExeWinExe
  • 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 运行只能注册一个测试主机启动器。

启动器执行以下操作:

  1. 它会检查描述测试可执行文件的一个 AppxManifest.xml
  2. 它将生成输出布局注册到 Windows。
  3. 它从已注册的包和清单应用程序 ID 解析应用的 AUMID。
  4. 它通过 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调用Exitfinally
失败的测试仍返回进程退出代码 0 将结果RunAsyncEnvironment.ExitCode分配给 。
未打包的运行失败,因为 AppxManifest.xml 缺少。 确认项目启用 MTP,并且运行不使用 VSTest。
打包的运行无法注册或激活应用。 确认特定于Windows的目标框架、开发人员模式或旁加载配置、完全信任的应用模型和清单可执行文件条目。

另见