Die App der Kladde läuft auf Ihrem Rechner und im Emulator. Zwischen diesem Zustand und einer App in fremder Hand liegen zwei Dinge: Beweise, dass sie tut, was sie soll, und ein Paket, das jemand installieren kann. Diese Lektion behandelt beides, in dieser Reihenfolge, und sie endet mit zwei Paketen auf einem Testgerät: ein signiertes Android-Paket und ein MSIX-Paket für Windows. In einen Store laden Sie in diesem Kurs nichts hoch.

Wie bisher gilt: Passen Sie die Namen an Ihre Projekte an. Die App heißt hier Kladde.App, die gemeinsame Bibliothek Kladde.Shared.

Was welcher Test prüft

Eine App hat mehr Orte, an denen etwas schiefgehen kann, als eine Webanwendung: das Gerät, die Plattform, den WebView, die Berechtigungen. Kein Test deckt alles ab. Die folgende Tabelle ordnet die Arten, die Sie kennen, und die, die dazukommen:

Test Läuft Prüft Prüft nicht
Unit-Test der ViewModels (Lektion W2.2.1) auf Ihrem Rechner, ohne Gerät Regeln, Befehle, Zustand wie etwas aussieht, echte Geräte
Komponententest mit bUnit (Lektion 2.7.6, Lektion W2.3.1) auf Ihrem Rechner das Markup einer Razor-Komponente, Ereignisse den echten WebView, echte Dienste
Gerätetest in einer Test-App auf Gerät oder Emulator Code, der Plattform-Aufrufe braucht das Zusammenspiel der Oberfläche
UI-Test mit Appium gegen die fertig installierte App Bedienung: tippen, eingeben, Seiten wechseln einzelne Regeln, dafür gibt es die Unit-Tests
Handprobe auf Geräten auf einem echten Gerät alles, was ein Mensch merkt Wiederholbarkeit

Unit-Tests: die Grenzen

Microsoft empfiehlt xUnit als Testframework für .NET-MAUI-Apps und beschreibt, wie man Code testbar macht. Es gibt zwei Wege. Beim ersten liegt der Code, den Sie testen, in einer Klassenbibliothek, die App und Testprojekt benutzen. Beim zweiten fügen Sie der App ein weiteres Zielframework hinzu, das keine Plattform nennt, etwa net10.0, und sorgen mit einer Bedingung dafür, dass die App für dieses Ziel keine ausführbare Datei erzeugt:

XML
<TargetFrameworks>net10.0;net10.0-android</TargetFrameworks>
<OutputType Condition="'$(TargetFramework)' != 'net10.0'">Exe</OutputType>

Microsofts Beispiel zeigt dasselbe mit einem älteren net9.0; Sie nehmen die Version Ihres Projekts. Ein Testprojekt ohne Plattform erzeugt keinen nativen MAUI-Kontext. Microsoft sagt dazu ausdrücklich: Navigation, Ausführung auf dem Oberflächen-Thread und Gerätedienste ersetzen Sie in solchen Tests durch Testdoppel. Sie prüfen dann nicht, wie etwas nativ gezeichnet wird, ob Berechtigungen stimmen und ob die echten Umsetzungen der ersetzten Dienste laufen.

Das heißt für die Kladde: Die ViewModels haben Sie in Lektion W2.2.1 ohne Gerät getestet, und BookingView in Lektion W2.3.1 mit bUnit. Beides sagt nichts darüber, ob MauiShareService auf einem echten Telefon eine Teilen-Seite öffnet. Das prüft ein Gerätetest oder die Handprobe.

Gerätetests

Brauchen Tests Plattform-Aufrufe oder native Steuerelemente, läuft der Test in einer Test-App auf einem Gerät oder Emulator. Microsoft nennt dafür Device Runner: eine Test-App mit einer sichtbaren Ansicht für die Ergebnisse und Haken, um die Tests von der Kommandozeile mit XHarness zu starten. Microsoft Learn verweist dafür auf das Wiki des Projekts Test Device Runners. Welche Versionen dafür nötig sind, haben wir nicht gelesen. Dieser Kurs baut keinen. Für .NET 11 nennt Microsoft eigene Vorlagen (androidtest und andere); das ist ein Ausblick, der Kurs bleibt bei .NET 10.

UI-Tests mit Appium

Appium ist ein quelloffenes Werkzeug, das native, hybride und Web-Apps über Plattformtreiber bedient, so wie es ein Mensch täte. Microsoft beschreibt es für .NET MAUI:

Plattform Treiber Läuft auf
Android UIAutomator2 Windows, macOS, Linux
iOS XCUITest nur macOS
Mac Catalyst Mac2 nur macOS
Windows Windows nur Windows

Auf einem Windows-Rechner testen Sie also Android und Windows, auf einem Mac Android, iOS und Mac Catalyst. Vorbereitet wird so:

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

Die erste Zeile braucht Node.js, die dritte den Treiber für Windows; der Server hört danach auf Port 4723. Für Windows nennt Microsoft außerdem den Windows Application Driver, und zwar genau in der Version 1.2.1; für Android muss ANDROID_HOME auf das Android-SDK zeigen.

Gefunden werden Elemente über die AutomationId, die Sie jedem Element geben, das ein Test bedienen soll:

XML
<Button x:Name="CounterBtn"
        AutomationId="CounterBtn"
        Text="Click me"
        Clicked="OnCounterClicked" />

Microsofts Beispiel legt für jede Plattform ein eigenes Testprojekt an und teilt den Testcode in einem gemeinsamen Projekt. Die Basisklasse steht dort so:

C#
public abstract class BaseTest
{
    protected AppiumDriver App => AppiumSetup.App;

    protected AppiumElement FindUIElement(string id)
    {
        if (App is WindowsDriver)
        {
            return App.FindElement(MobileBy.AccessibilityId(id));
        }

        return App.FindElement(MobileBy.Id(id));
    }
}

Ausgeführt wird ein Testprojekt je Plattform, etwa mit dotnet test UITests.Android/UITests.Android.csproj, nachdem die App auf dem Gerät oder im Emulator installiert ist. Zwei Besonderheiten für Android nennt Microsoft: In Debug-Builds muss NoReset auf true stehen, weil Appium sonst die Dateien der Schnellbereitstellung löscht, und die MainActivity braucht ein [Register]-Attribut mit dem Paketnamen. Das Beispiel von Microsoft benutzt NUnit; Ihre Unit-Tests bleiben bei xUnit.

Offen für diesen Kurs: Wie Appium Elemente im WebView eines BlazorWebView findet, haben wir nicht gelesen; die AutomationId gilt für native Steuerelemente. Für die Kladde heißt das: Sie testen mit Appium die Shell, die XAML-Seiten und das Öffnen der Buchungsansicht. Die Ansicht selbst prüft bUnit.