{"id":60962,"date":"2026-10-05T10:05:00","date_gmt":"2026-10-05T17:05:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=60962"},"modified":"2026-10-02T11:31:27","modified_gmt":"2026-10-02T18:31:27","slug":"testing-uwp-and-winui-3-apps-with-mstest","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/testing-uwp-and-winui-3-apps-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&#8217;s real UI dispatcher,\nnot just a single-threaded apartment (STA) thread, so that test setup, async\ntest code, and cleanup all run with UI-thread access. A WinUI 3 test still\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>\n4.5 and <a href=\"https:\/\/aka.ms\/testingplatform\">Microsoft.Testing.Platform<\/a> (MTP) 2.5,\nyou can use the same UI-thread testing pattern for UWP and WinUI 3 apps. The\nsupported models are classic and modern UWP, packaged or unpackaged WinUI 3,\nand WinUI hosts that use AppContainer.\n<code>MSTest.Sdk<\/code> picks the launch path for each model. It starts unpackaged apps\ndirectly and uses\n<a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.Testing.Extensions.PackagedApp\"><code>Microsoft.Testing.Extensions.PackagedApp<\/code><\/a>\nto register and activate packaged apps by AUMID. For AppContainer hosts, it\nalso grants the exact package SID access to the controller and report pipes.\nPackaged and sandboxed apps do not start as the initial test tool.\n<code>MSTest.Sdk<\/code> launches a normal full-trust sidecar controller that owns\ntest arguments, cancel requests, reports, retries, and the final exit code. It\nthen starts the app that hosts the tests. No <code>Microsoft.NET.Test.Sdk<\/code>,\n<code>vstest.console<\/code>, <code>UwpTestHostRuntimeProvider<\/code>, or Visual Studio deployment\nruntime is used.<\/p>\n<p>For more background, read the\n<a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/introducing-mstest-sdk\/\">introduction to MSTest.Sdk<\/a>\nand the overview of\n<a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/mtp-adoption-frameworks\/\">Microsoft.Testing.Platform support across .NET test frameworks<\/a>.<\/p>\n<p><div class=\"alert alert-info\"><p class=\"alert-divider\"><i class=\"fabric-icon fabric-icon--Info\"><\/i><strong>Packaged activation needs machine setup<\/strong><\/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.<\/div><\/p>\n<h2>Choose the model for UWP and WinUI 3 apps<\/h2>\n<p>Packaging and sandboxing are separate choices. Packaging adds MSIX\nidentity and AUMID activation; the trust level decides whether the process is\nfull trust or runs in AppContainer.<\/p>\n<p><img decoding=\"async\" src=\"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\nidentity, packaged activation contracts, or an exact match with installed app\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\nand select Microsoft.Testing.Platform for the native .NET 10\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>.\nMSTest.Sdk 4.5 includes MTP 2.5, the app-model sidecar controller, UWP\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&#8217;s XAML, manifest, architecture, and Native AOT settings. Then,\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\nimport <code>MSTest.Sdk<\/code> alongside <code>MSBuild.Sdk.Extras<\/code>. MSTest 4.5 includes the\nUAP-compatible adapter, generated bootstrap, packaged-app launcher, and TRX\nclient assets. The sidecar builds the <code>.build.appxrecipe<\/code> layout,\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\ntoolchain. However, they no longer need its VSTest runtime or deployment\nprovider.\nSee the <a href=\"https:\/\/github.com\/microsoft\/testfx\/blob\/main\/docs\/winui-testing.md\">UWP and WinUI testing guide<\/a>\nfor the complete classic project imports and package layout.<\/p>\n<p>Therefore, run UWP tests from a Developer PowerShell for Visual Studio. Build\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\nsupported <code>packagedClassicApp<\/code> AppContainer setup, keep the packaged WinUI host\nshown below and set <code>uap10:TrustLevel=\"appContainer\"<\/code> in the manifest. The\nhost still receives normal process arguments, while MTP grants only that\npackage SID access to its controller, cancellation, TRX, HangDump, and Retry\npipes. Do not grant <code>ALL APPLICATION PACKAGES<\/code>.<\/p>\n<p>Then, run this AppContainer shape from a non-elevated Developer PowerShell\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\nMSTest inside the app itself. Build this shared host once; the packaged and\nunpackaged deltas come afterward. Three pieces make up that shared project:<\/p>\n<p><img decoding=\"async\" src=\"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\nby Visual Studio&#8217;s &#8220;Windows application development&#8221; workload, or restored\nfrom NuGet if you build from the CLI). Then, start from Visual Studio&#8217;s\n&#8220;Blank App, Packaged (WinUI 3 in Desktop)&#8221; template, retain its\n<code>Package.appxmanifest<\/code> and package assets for the packaged form, and apply\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>.\n<code>MSTest.Sdk<\/code> detects that entry point, suppresses its own competing <code>Main<\/code>,\nand generates a reusable <code>MicrosoftTestingPlatformApplication.RunAsync<\/code>\nhelper. Finally, the app&#8217;s code-behind creates the window, publishes its\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\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\nreturns <code>void<\/code>, so without it a failing test run can look successful to a\nbuild or CI system. <code>MSTest.Sdk<\/code> owns MSTest references, extension\nregistration, and the packaged-app launcher registration. The\n<a href=\"https:\/\/github.com\/microsoft\/testfx\/blob\/main\/docs\/winui-testing.md\">WinUI testing guide<\/a>\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\nchecks that <code>TestInitialize<\/code>, the test body, and <code>TestCleanup<\/code> keep access to\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\ndispatcher. <code>[UITestMethod]<\/code> dispatches the full MSTest call for each test,\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\nyou chose in &#8220;Choose the model for UWP and WinUI 3 apps.&#8221; <code>MSTest.Sdk<\/code> keeps\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,\nMicrosoft.Testing.Platform uses its normal launch path, and this route does\nnot use VSTest&#8217;s 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\n<code>&lt;WindowsPackageType&gt;None&lt;\/WindowsPackageType&gt;<\/code> in the project. Retain the\ntemplate&#8217;s normal <code>Package.appxmanifest<\/code> and package assets. The output then\nhas MSIX identity, so Windows must register the package layout and activate the\ntest host by AUMID. It needs a Windows target framework moniker (TFM) at\n<code>10.0.19041.0<\/code> or later and Developer Mode or a similar sideloading policy for\nunsigned build output.<\/p>\n<p>In addition, <code>MSTest.Sdk<\/code> adds and registers the packaged-app launcher for\npackaged WinUI projects. Leave\n<code>TESTINGPLATFORM_PACKAGEDAPP_LAUNCHER<\/code> unset. Its default, <code>auto<\/code>, enables the\npackaged launch path only when a matching <code>AppxManifest.xml<\/code> describes the\napp. Otherwise it keeps the normal, faster launch path with no controller\nrestart or deployment-copy overhead. The\n<a href=\"https:\/\/github.com\/microsoft\/testfx\/blob\/main\/docs\/winui-testing.md\">WinUI testing guide<\/a>\ncovers the <code>always<\/code> and <code>never<\/code> overrides for less common scenarios.<\/p>\n<p><div class=\"alert alert-success\"><p class=\"alert-divider\"><i class=\"fabric-icon fabric-icon--Lightbulb\"><\/i><strong>Validate on your CI agent first<\/strong><\/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 &#8220;Packaged activation needs machine setup&#8221; above, before wiring this into a required gate.<\/div><\/p>\n<h3>Run it<\/h3>\n<p>Use <code>dotnet run<\/code> for either deployment model. It launches the generated\napphost, which hosts Microsoft.Testing.Platform inside the process that owns\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\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.\nHowever, do not use <code>dotnet exec<\/code>, which puts <code>dotnet.exe<\/code> in the middle and\ncan break WinUI resource loading.<\/p>\n<p>A window flashes briefly while the test runs, and the console reports a\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\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,\ncheck your actual CI agent image, not just a developer workstation, for a user\ncontext that can register the package, the required Developer Mode or\nsideloading policy, and the frameworks declared by the package. Otherwise, a\nworkstation that already has the UWP framework packages or Windows App SDK\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\nthe agent. A self-contained WinUI 3 build can remove that machine need, but test\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\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\n<code>MSTest.Sdk<\/code> into the existing project. For WinUI 3, set <code>UseWinUI<\/code> and\nchoose packaged or unpackaged deployment.<\/li>\n<li>Call the generated <code>MicrosoftTestingPlatformApplication.RunAsync<\/code> helper\nfrom <code>OnLaunched<\/code>. Modern UWP restores <code>args.Arguments<\/code> through\n<code>PackagedAppExtensions.GetTestApplicationArguments<\/code>; WinUI uses process\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\nAppContainer WinUI through the <code>InvokeTestingPlatform<\/code> MSBuild target from\na non-elevated Developer PowerShell.<\/li>\n<li>For packaged and AppContainer models, confirm Developer Mode (or your\nsideloading policy) and run non-elevated on the test agent.<\/li>\n<\/ol>\n<p><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><\/p>\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\nWindows app models. Let the SDK choose direct startup for unpackaged\nWinUI or the sidecar controller for package registration, AUMID activation,\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\nWinUI 3.<\/li>\n<li>Use direct apphost startup for unpackaged WinUI; let MTP register and\nAUMID-activate packaged or AppContainer hosts.<\/li>\n<li>Validate the exact package model, required frameworks, trust level, and\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>\nand the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/testing\/unit-testing-with-mstest\">MSTest documentation<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to test UWP and WinUI 3 apps with MSTest and Microsoft.Testing.Platform across packaged, unpackaged, and AppContainer hosts.<\/p>\n","protected":false},"author":140087,"featured_media":60968,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,489],"tags":[8197,7784,136,143,8217,8216],"class_list":["post-60962","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-xaml","tag-microsoft-testing-platform","tag-mstest","tag-testing","tag-uwp","tag-windows-app-sdk","tag-winui-3"],"acf":[],"blog_post_summary":"<p>Learn how to test UWP and WinUI 3 apps with MSTest and Microsoft.Testing.Platform across packaged, unpackaged, and AppContainer hosts.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/60962","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/140087"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=60962"}],"version-history":[{"count":1,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/60962\/revisions"}],"predecessor-version":[{"id":60967,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/60962\/revisions\/60967"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/60968"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=60962"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=60962"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=60962"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}