{"id":5226,"date":"2026-10-05T17:13:10","date_gmt":"2026-10-05T17:13:10","guid":{"rendered":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2026\/10\/05\/uwp-and-winui-3-apps-ui-testing-with-mstest\/"},"modified":"2026-10-05T17:13:10","modified_gmt":"2026-10-05T17:13:10","slug":"uwp-and-winui-3-apps-ui-testing-with-mstest","status":"publish","type":"post","link":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2026\/10\/05\/uwp-and-winui-3-apps-ui-testing-with-mstest\/","title":{"rendered":"UWP and WinUI 3 apps: UI testing with MSTest"},"content":{"rendered":"<p>Reliable testing of UWP and WinUI 3 apps needs the app\u2019s real UI dispatcher,<br \/>\nnot just a single-threaded apartment (STA) thread, so that test setup, async<br \/>\ntest code, and cleanup all run with UI-thread access. A WinUI 3 test still<br \/>\nlooks this simple:<\/p>\n<pre><code class=\"language-csharp\">[UITestMethod]\npublic async Task GridCanBeCreatedOnTheUIThread()\n{\n    await Task.Yield();\n\n    var grid = new Grid();\n\n    Assert.IsTrue(grid.DispatcherQueue.HasThreadAccess);\n}<\/code><\/pre>\n<p>With <a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/testing\/unit-testing-with-mstest\">MSTest<\/a><br \/>\n4.5 and <a href=\"https:\/\/aka.ms\/testingplatform\">Microsoft.Testing.Platform<\/a> (MTP) 2.5,<br \/>\nyou can use the same UI-thread testing pattern for UWP and WinUI 3 apps. The<br \/>\nsupported models are classic and modern UWP, packaged or unpackaged WinUI 3,<br \/>\nand WinUI hosts that use AppContainer.<br \/>\n<code>MSTest.Sdk<\/code> picks the launch path for each model. It starts unpackaged apps<br \/>\ndirectly and uses<br \/>\n<a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.Testing.Extensions.PackagedApp\"><code>Microsoft.Testing.Extensions.PackagedApp<\/code><\/a><br \/>\nto register and activate packaged apps by AUMID. For AppContainer hosts, it<br \/>\nalso grants the exact package SID access to the controller and report pipes.<br \/>\nPackaged and sandboxed apps do not start as the initial test tool.<br \/>\n<code>MSTest.Sdk<\/code> launches a normal full-trust sidecar controller that owns<br \/>\ntest arguments, cancel requests, reports, retries, and the final exit code. It<br \/>\nthen starts the app that hosts the tests. No <code>Microsoft.NET.Test.Sdk<\/code>,<br \/>\n<code>vstest.console<\/code>, <code>UwpTestHostRuntimeProvider<\/code>, or Visual Studio deployment<br \/>\nruntime is used.<\/p>\n<p>For more background, read the<br \/>\n<a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/introducing-mstest-sdk\/\">introduction to MSTest.Sdk<\/a><br \/>\nand the overview of<br \/>\n<a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/mtp-adoption-frameworks\/\">Microsoft.Testing.Platform support across .NET test frameworks<\/a>.<\/p>\n\n<div class=\"alert alert-info\">\n<p class=\"alert-divider\"><i class=\"fabric-icon fabric-icon--Info\"><\/i><strong>Packaged activation needs machine setup<\/strong><\/p>\n<p>To register an unsigned build-output layout, you need Developer Mode or a similar sideloading policy. Therefore, run AppContainer tests non-elevated, and confirm the policy on your CI agent, not just your workstation.<\/p><\/div>\n<h2>Choose the model for UWP and WinUI 3 apps<\/h2>\n<p>Packaging and sandboxing are separate choices. Packaging adds MSIX<br \/>\nidentity and AUMID activation; the trust level decides whether the process is<br \/>\nfull trust or runs in AppContainer.<\/p>\n<p><img data-opt-id=1021893353  fetchpriority=\"high\" decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/testing-uwp-and-winui-3-apps-with-mstest\/mstest-windows-app-hosting.svg\" alt=\"Application models for UWP and WinUI 3 apps select direct startup or package registration and AUMID activation\" \/><\/p>\n<table>\n<thead>\n<tr>\n<th>Application model<\/th>\n<th>Identity and trust<\/th>\n<th>MTP test-host path<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><a href=\"https:\/\/github.com\/microsoft\/testfx\/tree\/main\/samples\/public\/ClassicUwpMtpApp\">Classic UWP<\/a> (<code>uap10.0<\/code>)<\/td>\n<td>MSIX, AppContainer<\/td>\n<td>Sidecar controller, UAP adapter\/bootstrap assets, AUMID activation<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/github.com\/microsoft\/testfx\/tree\/main\/samples\/public\/UwpMtpApp\">Modern UWP<\/a> (<code>UseUwp<\/code>)<\/td>\n<td>MSIX, AppContainer<\/td>\n<td>Sidecar controller, Native AOT host, AUMID activation<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/github.com\/microsoft\/testfx\/tree\/main\/samples\/public\/WinUIMtpUnpackagedApp\">Unpackaged WinUI 3<\/a><\/td>\n<td>No package identity, full trust<\/td>\n<td>Direct apphost launch<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/github.com\/microsoft\/testfx\/tree\/main\/samples\/public\/WinUIMtpPackagedApp\">Packaged WinUI 3<\/a><\/td>\n<td>MSIX, full trust<\/td>\n<td>Sidecar controller, package registration, AUMID activation<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/github.com\/microsoft\/testfx\/tree\/main\/samples\/public\/WinUIMtpAppContainerApp\">WinUI 3 <code>packagedClassicApp<\/code> with AppContainer trust<\/a><\/td>\n<td>MSIX, AppContainer<\/td>\n<td>Sidecar controller and exact package-SID pipe authorization<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>For WinUI, start unpackaged unless the behavior under test needs package<br \/>\nidentity, packaged activation contracts, or an exact match with installed app<br \/>\nbehavior. In contrast, UWP is inherently packaged and sandboxed.<\/p>\n<h2>Select MSTest.Sdk and MTP for UWP and WinUI 3 apps<\/h2>\n<p>At the solution or repo root, use <code>global.json<\/code> to pin MSTest.Sdk 4.5<br \/>\nand select Microsoft.Testing.Platform for the native .NET 10<br \/>\n<code>dotnet test<\/code> experience:<\/p>\n<pre><code class=\"language-json\">{\n  \"test\": {\n    \"runner\": \"Microsoft.Testing.Platform\"\n  },\n  \"msbuild-sdks\": {\n    \"MSTest.Sdk\": \"4.5.0\"\n  }\n}<\/code><\/pre>\n<p>Otherwise, .NET 10 uses VSTest for <code>dotnet test<\/code>.<br \/>\nMSTest.Sdk 4.5 includes MTP 2.5, the app-model sidecar controller, UWP<br \/>\nadapter\/bootstrap assets, and the packaged launcher.<\/p>\n<h2>Configure UWP and WinUI 3 apps<\/h2>\n<h3>Modern UWP<\/h3>\n<p>For a modern UWP project, the test setup is small:<\/p>\n<pre><code class=\"language-xml\">&lt;Project Sdk=\"MSTest.Sdk\"&gt;\n  &lt;PropertyGroup&gt;\n    &lt;TargetFramework&gt;net10.0-windows10.0.26100.0&lt;\/TargetFramework&gt;\n    &lt;UseUwp&gt;true&lt;\/UseUwp&gt;\n    &lt;PublishAot&gt;true&lt;\/PublishAot&gt;\n  &lt;\/PropertyGroup&gt;\n&lt;\/Project&gt;<\/code><\/pre>\n<p>Keep the app\u2019s XAML, manifest, architecture, and Native AOT settings. Then,<br \/>\nfrom <code>OnLaunched<\/code>, pass the activation string to the generated MTP helper:<\/p>\n<pre><code class=\"language-csharp\">using Microsoft.Testing.Extensions;\n\nprotected override async void OnLaunched(LaunchActivatedEventArgs args)\n{\n    Window.Current.Activate();\n    string[] testArguments =\n        PackagedAppExtensions.GetTestApplicationArguments(args.Arguments);\n    Environment.ExitCode =\n        await MicrosoftTestingPlatformApplication.RunAsync(testArguments);\n    Exit();\n}<\/code><\/pre>\n<h3>Classic UWP<\/h3>\n<p>Classic <code>uap10.0<\/code> projects keep their existing UWP project structure and<br \/>\nimport <code>MSTest.Sdk<\/code> alongside <code>MSBuild.Sdk.Extras<\/code>. MSTest 4.5 includes the<br \/>\nUAP-compatible adapter, generated bootstrap, packaged-app launcher, and TRX<br \/>\nclient assets. The sidecar builds the <code>.build.appxrecipe<\/code> layout,<br \/>\ninstalls its declared frameworks, and starts the app by AUMID.<\/p>\n<p>Classic and modern UWP builds still need the Visual Studio MSBuild\/UWP<br \/>\ntoolchain. However, they no longer need its VSTest runtime or deployment<br \/>\nprovider.<br \/>\nSee the <a href=\"https:\/\/github.com\/microsoft\/testfx\/blob\/main\/docs\/winui-testing.md\">UWP and WinUI testing guide<\/a><br \/>\nfor the complete classic project imports and package layout.<\/p>\n<p>Therefore, run UWP tests from a Developer PowerShell for Visual Studio. Build<br \/>\nwith the desktop MSBuild toolchain, then invoke the MTP target:<\/p>\n<pre><code class=\"language-powershell\">msbuild .MyUwpTests.sln \/restore \/p:Configuration=Release \/p:Platform=x64\nmsbuild .MyUwpTests.csproj \/t:InvokeTestingPlatform \/p:Configuration=Release \/p:Platform=x64<\/code><\/pre>\n<h3>AppContainer-configured WinUI 3<\/h3>\n<p>A packaged WinUI 3 app is full trust by default. For example, to test a<br \/>\nsupported <code>packagedClassicApp<\/code> AppContainer setup, keep the packaged WinUI host<br \/>\nshown below and set <code>uap10:TrustLevel=\"appContainer\"<\/code> in the manifest. The<br \/>\nhost still receives normal process arguments, while MTP grants only that<br \/>\npackage SID access to its controller, cancellation, TRX, HangDump, and Retry<br \/>\npipes. Do not grant <code>ALL APPLICATION PACKAGES<\/code>.<\/p>\n<p>Then, run this AppContainer shape from a non-elevated Developer PowerShell<br \/>\nthrough the MTP MSBuild target:<\/p>\n<pre><code class=\"language-powershell\">dotnet build .MyAppContainerTests.csproj -c Release -p:Platform=x64\ndotnet msbuild .MyAppContainerTests.csproj \/t:InvokeTestingPlatform \/p:Configuration=Release \/p:Platform=x64<\/code><\/pre>\n<h2>Build the self-hosted WinUI 3 test app<\/h2>\n<p>The following complete WinUI 3 test app supplies that dispatcher and runs<br \/>\nMSTest inside the app itself. Build this shared host once; the packaged and<br \/>\nunpackaged deltas come afterward. Three pieces make up that shared project:<\/p>\n<p><img data-opt-id=1904757482  fetchpriority=\"high\" decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/testing-uwp-and-winui-3-apps-with-mstest\/winui-mstest-project-layout.svg\" alt=\"The csproj configures the MSTest runner; UnitTestApp hosts the platform; test classes run on its published dispatcher\" \/><\/p>\n<h3>Configure the shared project<\/h3>\n<p>You need Windows, the .NET 10 SDK, and the Windows App SDK tooling (installed<br \/>\nby Visual Studio\u2019s \u201cWindows application development\u201d workload, or restored<br \/>\nfrom NuGet if you build from the CLI). Then, start from Visual Studio\u2019s<br \/>\n\u201cBlank App, Packaged (WinUI 3 in Desktop)\u201d template, retain its<br \/>\n<code>Package.appxmanifest<\/code> and package assets for the packaged form, and apply<br \/>\nthis shared project setup.<\/p>\n<pre><code class=\"language-xml\">&lt;Project Sdk=\"MSTest.Sdk\"&gt;\n  &lt;PropertyGroup&gt;\n    &lt;OutputType&gt;Exe&lt;\/OutputType&gt;\n    &lt;TargetFramework&gt;net10.0-windows10.0.19041.0&lt;\/TargetFramework&gt;\n    &lt;TargetPlatformMinVersion&gt;10.0.17763.0&lt;\/TargetPlatformMinVersion&gt;\n    &lt;UseWinUI&gt;true&lt;\/UseWinUI&gt;\n    &lt;ImplicitUsings&gt;enable&lt;\/ImplicitUsings&gt;\n    &lt;Nullable&gt;enable&lt;\/Nullable&gt;\n  &lt;\/PropertyGroup&gt;\n\n  &lt;ItemGroup&gt;\n    &lt;Page Remove=\"UnitTestApp.xaml\" \/&gt;\n    &lt;ApplicationDefinition Include=\"UnitTestApp.xaml\" \/&gt;\n    &lt;ProjectCapability Include=\"TestContainer\" \/&gt;\n  &lt;\/ItemGroup&gt;\n\n  &lt;ItemGroup&gt;\n    &lt;PackageReference Include=\"Microsoft.WindowsAppSDK\"\n                      Version=\"1.8.251106002\" \/&gt;\n  &lt;\/ItemGroup&gt;\n&lt;\/Project&gt;<\/code><\/pre>\n<h3>Define the application entry point<\/h3>\n<p>The <code>ApplicationDefinition<\/code> points to this minimal <code>UnitTestApp.xaml<\/code>:<\/p>\n<pre><code class=\"language-xml\">&lt;Application\n    x:Class=\"MyWinUiTests.UnitTestApp\"\n    xmlns=\"http:\/\/schemas.microsoft.com\/winfx\/2006\/xaml\/presentation\"\n    xmlns:x=\"http:\/\/schemas.microsoft.com\/winfx\/2006\/xaml\"&gt;\n  &lt;Application.Resources \/&gt;\n&lt;\/Application&gt;<\/code><\/pre>\n<h3>Host the test run from OnLaunched<\/h3>\n<p>The WinUI app owns its entry point through this <code>ApplicationDefinition<\/code>.<br \/>\n<code>MSTest.Sdk<\/code> detects that entry point, suppresses its own competing <code>Main<\/code>,<br \/>\nand generates a reusable <code>MicrosoftTestingPlatformApplication.RunAsync<\/code><br \/>\nhelper. Finally, the app\u2019s code-behind creates the window, publishes its<br \/>\ndispatcher, and calls that helper:<\/p>\n<pre><code class=\"language-csharp\">using Microsoft.UI.Xaml;\nusing Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;\n\nnamespace MyWinUiTests;\n\npublic partial class UnitTestApp : Application\n{\n    private Window? _window;\n\n    public UnitTestApp() =&gt; InitializeComponent();\n\n    protected override async void OnLaunched(LaunchActivatedEventArgs args)\n    {\n        _window = new Window();\n        _window.Activate();\n        UITestMethodAttribute.DispatcherQueue = _window.DispatcherQueue;\n\n        try\n        {\n            Environment.ExitCode = await MicrosoftTestingPlatformApplication.RunAsync(Environment.GetCommandLineArgs()[1..]);\n        }\n        finally\n        {\n            _window.Close();\n            Exit();\n        }\n    }\n}<\/code><\/pre>\n<p>That single <code>OnLaunched<\/code> override plays out in this order every time the app<br \/>\nstarts, whether launched directly or activated by AUMID:<\/p>\n<pre><code class=\"language-mermaid\">sequenceDiagram\n    participant OS as Windows\n    participant App as UnitTestApp.OnLaunched\n    participant MTP as Microsoft.Testing.Platform\n    participant Tests as MSTest UITestMethod tests\n\n    OS-&gt;&gt;App: Launch (apphost or AUMID activation)\n    App-&gt;&gt;App: Create and activate the Window\n    App-&gt;&gt;Tests: Publish UITestMethodAttribute.DispatcherQueue\n    App-&gt;&gt;MTP: MicrosoftTestingPlatformApplication.RunAsync\n    MTP-&gt;&gt;Tests: Run tests on the published dispatcher\n    MTP--&gt;&gt;App: Test-run result\n    App-&gt;&gt;App: Environment.ExitCode = result\n    App-&gt;&gt;OS: Window.Close + Exit<\/code><\/pre>\n<p>Assigning <code>Environment.ExitCode<\/code> is important: a WinUI-generated entry point<br \/>\nreturns <code>void<\/code>, so without it a failing test run can look successful to a<br \/>\nbuild or CI system. <code>MSTest.Sdk<\/code> owns MSTest references, extension<br \/>\nregistration, and the packaged-app launcher registration. The<br \/>\n<a href=\"https:\/\/github.com\/microsoft\/testfx\/blob\/main\/docs\/winui-testing.md\">WinUI testing guide<\/a><br \/>\ncovers the generated helper and hosting model in more depth.<\/p>\n<h3>Verify the dispatcher in a UI test<\/h3>\n<p>The app and tests now form one host. For example, this async test<br \/>\nchecks that <code>TestInitialize<\/code>, the test body, and <code>TestCleanup<\/code> keep access to<br \/>\nthe UI dispatcher:<\/p>\n<pre><code class=\"language-csharp\">using Microsoft.UI.Dispatching;\nusing Microsoft.UI.Xaml.Controls;\nusing Microsoft.VisualStudio.TestTools.UnitTesting;\n\nnamespace MyWinUiTests;\n\n[TestClass]\npublic sealed class ViewTests\n{\n    private bool _initializedOnUiThread;\n    private bool _verifyCleanupOnUiThread;\n\n    [TestInitialize]\n    public async Task InitializeAsync()\n    {\n        await Task.Yield();\n        _initializedOnUiThread =\n            DispatcherQueue.GetForCurrentThread()?.HasThreadAccess == true;\n    }\n\n    [TestCleanup]\n    public async Task CleanupAsync()\n    {\n        await Task.Yield();\n\n        if (_verifyCleanupOnUiThread)\n        {\n            Assert.IsTrue(\n                DispatcherQueue.GetForCurrentThread()?.HasThreadAccess == true);\n        }\n    }\n\n    [UITestMethod]\n    public async Task ControlCanBeCreatedAfterAsyncInitialization()\n    {\n        _verifyCleanupOnUiThread = true;\n        await Task.Yield();\n\n        var grid = new Grid();\n\n        Assert.IsTrue(_initializedOnUiThread);\n        Assert.IsTrue(grid.DispatcherQueue.HasThreadAccess);\n    }\n}<\/code><\/pre>\n<p><code>[STATestMethod]<\/code> can provide an STA thread, but it does not create a WinUI<br \/>\ndispatcher. <code>[UITestMethod]<\/code> dispatches the full MSTest call for each test,<br \/>\nincluding its setup and cleanup.<\/p>\n<h2>Apply deployment models to UWP and WinUI 3 apps<\/h2>\n<p>For UWP and WinUI 3 apps, apply the delta that matches the deployment model<br \/>\nyou chose in \u201cChoose the model for UWP and WinUI 3 apps.\u201d <code>MSTest.Sdk<\/code> keeps<br \/>\nthe runner setup shared between both models.<\/p>\n<h3>Unpackaged WinUI 3 (default choice)<\/h3>\n<p>Add these properties and do not include MSIX manifest or package asset items:<\/p>\n<pre><code class=\"language-xml\">&lt;PropertyGroup&gt;\n  &lt;WindowsPackageType&gt;None&lt;\/WindowsPackageType&gt;\n  &lt;EnableMsixTooling&gt;false&lt;\/EnableMsixTooling&gt;\n&lt;\/PropertyGroup&gt;<\/code><\/pre>\n<p>The resulting apphost is a standard executable. As a result,<br \/>\nMicrosoft.Testing.Platform uses its normal launch path, and this route does<br \/>\nnot use VSTest\u2019s appx runtime provider.<\/p>\n<h3>Packaged full-trust WinUI 3 (when you need identity)<\/h3>\n<p>Remove the two unpackaged overrides; do not leave<br \/>\n<code>&lt;WindowsPackageType&gt;None&lt;\/WindowsPackageType&gt;<\/code> in the project. Retain the<br \/>\ntemplate\u2019s normal <code>Package.appxmanifest<\/code> and package assets. The output then<br \/>\nhas MSIX identity, so Windows must register the package layout and activate the<br \/>\ntest host by AUMID. It needs a Windows target framework moniker (TFM) at<br \/>\n<code>10.0.19041.0<\/code> or later and Developer Mode or a similar sideloading policy for<br \/>\nunsigned build output.<\/p>\n<p>In addition, <code>MSTest.Sdk<\/code> adds and registers the packaged-app launcher for<br \/>\npackaged WinUI projects. Leave<br \/>\n<code>TESTINGPLATFORM_PACKAGEDAPP_LAUNCHER<\/code> unset. Its default, <code>auto<\/code>, enables the<br \/>\npackaged launch path only when a matching <code>AppxManifest.xml<\/code> describes the<br \/>\napp. Otherwise it keeps the normal, faster launch path with no controller<br \/>\nrestart or deployment-copy overhead. The<br \/>\n<a href=\"https:\/\/github.com\/microsoft\/testfx\/blob\/main\/docs\/winui-testing.md\">WinUI testing guide<\/a><br \/>\ncovers the <code>always<\/code> and <code>never<\/code> overrides for less common scenarios.<\/p>\n\n<div class=\"alert alert-success\">\n<p class=\"alert-divider\"><i class=\"fabric-icon fabric-icon--Lightbulb\"><\/i><strong>Validate on your CI agent first<\/strong><\/p>\n<p>Confirm Developer Mode (or your sideloading policy) and a clean, passing exit code on your own packaged app and CI agent, as covered in \u201cPackaged activation needs machine setup\u201d above, before wiring this into a required gate.<\/p><\/div>\n<h3>Run it<\/h3>\n<p>Use <code>dotnet run<\/code> for either deployment model. It launches the generated<br \/>\napphost, which hosts Microsoft.Testing.Platform inside the process that owns<br \/>\nthe window and dispatcher:<\/p>\n<pre><code class=\"language-powershell\">dotnet run<\/code><\/pre>\n<p>The .NET 10 native MTP runner also supports <code>dotnet test<\/code> for either<br \/>\ndeployment model:<\/p>\n<pre><code class=\"language-powershell\">dotnet test --project .MyWinUiTests.csproj -c Release -a x64<\/code><\/pre>\n<p>For an unpackaged app, you can also launch the generated apphost directly.<br \/>\nHowever, do not use <code>dotnet exec<\/code>, which puts <code>dotnet.exe<\/code> in the middle and<br \/>\ncan break WinUI resource loading.<\/p>\n<p>A window flashes briefly while the test runs, and the console reports a<br \/>\nsummary:<\/p>\n<pre><code class=\"language-text\">Passed! - Failed: 0, Passed: 1, Skipped: 0, Total: 1, Duration: 63ms - MyWinUiTests.dll (net10.0-windows10.0.19041.0)<\/code><\/pre>\n<p>The packaged development layout can remain registered after the run. Remove<br \/>\nit when needed by using its manifest <code>Identity<\/code> name:<\/p>\n<pre><code class=\"language-powershell\">Get-AppxPackage -Name '&lt;package identity name&gt;' |\n  Remove-AppxPackage -PreserveApplicationData<\/code><\/pre>\n<h2>Validate UWP and WinUI 3 apps on the target machine<\/h2>\n<p>For a packaged test host, a passing build is only the first step. Therefore,<br \/>\ncheck your actual CI agent image, not just a developer workstation, for a user<br \/>\ncontext that can register the package, the required Developer Mode or<br \/>\nsideloading policy, and the frameworks declared by the package. Otherwise, a<br \/>\nworkstation that already has the UWP framework packages or Windows App SDK<br \/>\nruntime installed can hide a gap that only appears on a clean build agent.<\/p>\n<p>Framework-dependent WinUI 3 apps need the matching Windows App SDK runtime on<br \/>\nthe agent. A self-contained WinUI 3 build can remove that machine need, but test<br \/>\nit using the exact package model that will run in CI.<\/p>\n<h2>Start testing UWP and WinUI 3 apps<\/h2>\n<p>Use this checklist to start testing UWP and WinUI 3 apps:<\/p>\n<ol>\n<li>Select Microsoft.Testing.Platform in <code>global.json<\/code> and use<br \/>\n<code>MSTest.Sdk<\/code> 4.5.<\/li>\n<li>For modern UWP, set <code>UseUwp<\/code> and <code>PublishAot<\/code>. For classic UWP, import<br \/>\n<code>MSTest.Sdk<\/code> into the existing project. For WinUI 3, set <code>UseWinUI<\/code> and<br \/>\nchoose packaged or unpackaged deployment.<\/li>\n<li>Call the generated <code>MicrosoftTestingPlatformApplication.RunAsync<\/code> helper<br \/>\nfrom <code>OnLaunched<\/code>. Modern UWP restores <code>args.Arguments<\/code> through<br \/>\n<code>PackagedAppExtensions.GetTestApplicationArguments<\/code>; WinUI uses process<br \/>\narguments. Publish the UI dispatcher where required.<\/li>\n<li>Run full-trust WinUI with <code>dotnet run<\/code> or <code>dotnet test<\/code>. Run UWP and<br \/>\nAppContainer WinUI through the <code>InvokeTestingPlatform<\/code> MSBuild target from<br \/>\na non-elevated Developer PowerShell.<\/li>\n<li>For packaged and AppContainer models, confirm Developer Mode (or your<br \/>\nsideloading policy) and run non-elevated on the test agent.<\/li>\n<\/ol>\n<div class=\"d-flex justify-content-center\"><a class=\"cta_button_link btn-primary mb-24\" href=\"https:\/\/github.com\/microsoft\/testfx\/blob\/main\/docs\/winui-testing.md\" target=\"_blank\">Get the UWP and WinUI testing guide<\/a><\/div>\n<h2>One test platform for UWP and WinUI 3 apps<\/h2>\n<p>Keep <code>MSTest.Sdk<\/code>, the generated MTP helper, and <code>[UITestMethod]<\/code> across the<br \/>\nWindows app models. Let the SDK choose direct startup for unpackaged<br \/>\nWinUI or the sidecar controller for package registration, AUMID activation,<br \/>\nand AppContainer isolation.<\/p>\n<p>Three takeaways to carry forward:<\/p>\n<ul>\n<li>Reuse the same MSTest lifecycle and UI-dispatcher tests across UWP and<br \/>\nWinUI 3.<\/li>\n<li>Use direct apphost startup for unpackaged WinUI; let MTP register and<br \/>\nAUMID-activate packaged or AppContainer hosts.<\/li>\n<li>Validate the exact package model, required frameworks, trust level, and<br \/>\nmachine policy that your CI agents will run.<\/li>\n<\/ul>\n<p>For more detail, see the <a href=\"https:\/\/github.com\/microsoft\/testfx\/blob\/main\/docs\/winui-testing.md\">UWP and WinUI testing guide<\/a><br \/>\nand the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/testing\/unit-testing-with-mstest\">MSTest documentation<\/a>.<\/p>\n<p>The post <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/testing-uwp-and-winui-3-apps-with-mstest\/\">UWP and WinUI 3 apps: UI testing with MSTest<\/a> appeared first on <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\">.NET Blog<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>Reliable testing of UWP and WinUI 3 apps needs the app\u2019s real UI dispatcher, not just a single-threaded apartment (STA) [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":94,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[7],"tags":[],"class_list":["post-5226","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet"],"_links":{"self":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/5226","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/comments?post=5226"}],"version-history":[{"count":0,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/5226\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media\/94"}],"wp:attachment":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media?parent=5226"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/categories?post=5226"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/tags?post=5226"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}