The Kladde runs on your machine. Between that state and a program in someone else's hands lie two things: evidence that it does what it should, and a package that someone can install. The lesson covers both in this order and ends with a signed MSIX package that you have installed and removed again, and with a list of the data the app processes. You upload nothing to a store in this course. If you want to package an existing WPF or Windows Forms program or distribute it with ClickOnce, you will find that in the Modernization course.

As before: src/Kladde.Desktop (the app), src/Kladde.Desktop.Logic (the library), tests/Kladde.Desktop.Logic.Tests. Adapt the names to your projects.

State of the checks. The commands for building, signing, installing and publishing and all project properties come from Microsoft Learn and were not run; when this was written no Windows machine with the WinUI tools and no signtool was available. An output is therefore described, never shown. File names of packages and folders in the build result depend on your project and are not invented here. Only the plain classes of the library from lesson 0301 were run, with their xUnit tests (.NET 10, exit code 0). Where Learn differs between two places, it says open. Work through the exercises on a Windows machine and compare every step with the linked page.

What each test verifies

A Windows app has more places for errors than a web page: window, package, permissions, scaling, keyboard. No test covers everything.

Test Runs Verifies Does not verify
xUnit test of the view models and rules (lesson 0201) in Kladde.Desktop.Logic.Tests on your machine, without a window rules, commands, state, error cases how something looks, whether a XAML binding takes effect
Test with [UITestMethod] in a WinUI test app in an app with a UI thread code that needs Microsoft.UI.Xaml types how the whole user interface works together
UI test with Appium and the Windows driver against the running, finished app operation: clicking, typing, switching pages individual rules; that is what the unit tests are for
Accessibility Insights for Windows against the running app the UI Automation tree whether the app calculates correctly
Playwright against WebView2 parts the web content in the app the native controls
Manual check on a real machine, preferably a fresh one what a person notices, including the package itself repeatability

Why code belongs in a library

Most types from Microsoft.UI.Xaml can only be used on the UI thread of a XAML application. Learn therefore recommends moving the code to be tested out of the app project into a library project that the app and the test project both reference. That is exactly what the Kladde has done since lesson 0201: view models, rules, the reminder planner and the placement rule from 0301 live in Kladde.Desktop.Logic and run with xUnit, without a window. That dotnet test returns exit code 0 is the quickest evidence you have, and it belongs in every change. Read the code, not the message "Passed": check $LASTEXITCODE.

An xUnit, NUnit or MSTest project that references a WinUI project needs three adjustments according to Learn: The TargetFramework must match that of the WinUI project (for example net10.0-windows10.0.19041.0, not net10.0), the RuntimeIdentifiers must be right (win-x86;win-x64;win-arm64), and <WindowsAppSdkBootstrapInitialize>true</WindowsAppSdkBootstrapInitialize> makes the test load the Windows App SDK runtime. In addition, the runtime must be installed on the machine. Your library references no WinUI and needs none of this.

Tests with UITestMethod

If a test needs a real user interface (a UserControl, a control), it runs in a WinUI test app. In Visual Studio the template is called "WinUI Unit Test App"; it creates an app that starts a UI thread and runs the tests on it. Tests that need this thread carry [UITestMethod] instead of [TestMethod]:

C#
[UITestMethod]
public void TestUserControl1()
{
    var control = new WinUIClassLibrary1.UserControl1();
    Assert.AreEqual(7, control.GetSeven());
}

Learn's walkthrough creates a WinUI class library with the UserControl and references it from the test: the same idea, that the code lives in a library and not in the app.

MSTest with Microsoft.Testing.Platform

For WinUI 3 projects, Learn also names the route through MSTest and the Microsoft.Testing.Platform (MTP). The statements in brief: Packaged WinUI 3 apps with full trust, unpackaged ones and those in the AppContainer are supported. The project uses MSTest.Sdk 4.5 or later, sets UseWinUI to true and targets a Windows target framework. For an unpackaged app, WindowsPackageType is None and MTP starts the .exe directly; for a packaged one, a helper process registers the package and starts the app. VSTest does not support unpackaged WinUI 3 apps. You build and run for a fixed architecture:

PowerShell
dotnet build -p:Platform=x64
dotnet test --project . --no-build -p:Platform=x64

Learn names three pitfalls: Failed tests return exit code 0 if the result of the MTP run did not end up in Environment.ExitCode. The process stays open if the test window is not closed and Exit is not called. And dotnet exec does not work, because WinUI looks for its resources relative to the process path. Learn gives full support as of MSTest 4.5 and MTP 2.5; until the stable versions are released, you need matching preview packages. Check the state before you rely on it. The course sticks with xUnit for the library (lesson 0201) and names MSTest for the tests that need XAML types.

UI tests with Appium

WinAppDriver was Microsoft's tool for UI tests on Windows and, according to Learn, is no longer being developed. The recommended successor is Appium with the Windows driver (appium-windows-driver); both speak the WebDriver protocol and operate Windows programs through UI Automation. The preparation according to Learn, with Node.js:

PowerShell
npm install -g appium
appium driver install windows
appium driver list
appium

The third line should show windows as installed, the fourth starts the server. You write the test with a WebDriver library (there is one for C#); for a packaged app the capability app names the AUMID, for an unpackaged one the path of the .exe. Which property of a WinUI element Appium takes as the identifier (AutomationProperties.AutomationId is usual) we have not read for WinUI: open; for MAUI (course W2) the identifier is AutomationId, but that is a different user interface.

Accessibility Insights for Windows checks the same UI Automation tree that test tools use as well: If it is well built, that helps testability and accessibility. Playwright can connect to WebView2 instances, if the Kladde shows web content; it does not see the native controls.