Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Da sich Ihre ViewModels und Dienste nun in einer separaten Klassenbibliothek befinden, können Sie einfach Komponententests erstellen. Durch das Hinzufügen von Komponententestprojekten können Sie überprüfen, ob sich Ihre ViewModels und Dienste wie erwartet verhalten, ohne sich auf die UI-Ebene oder manuelle Tests zu verlassen. Sie können Unit-Tests automatisch als Bestandteil Ihres Entwicklungsworkflows ausführen, um sicherzustellen, dass Ihr Code zuverlässig und gewartet werden kann.
Erstellen eines Komponententestprojekts
- Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf die Lösung.
- Wählen Sie "Neues Projekt>" aus.
- Wählen Sie die WinUI Unit Test App-Vorlage und dann "Weiter" aus.
- Geben Sie dem Projekt den Namen
WinUINotes.Tests, und wählen Sie Erstellen aus.
Hinzufügen von Projektverweisen
- Klicken Sie mit der rechten Maustaste auf das Projekt WinUINotes.Tests, und wählen Sie "> hinzufügen" aus.
- Überprüfen Sie das WinUINotes.Bus-Projekt , und wählen Sie "OK" aus.
Erstellen gefälschter Implementierungen für Tests
Erstellen Sie zum Testen gefälschte Implementierungen des Dateidiensts und Speicherklassen, die nicht tatsächlich auf den Datenträger schreiben. Fakes sind einfache Implementierungen, die das Verhalten realer Abhängigkeiten zu Testzwecken simulieren.
Erstellen Sie im Projekt WinUINotes.Tests einen neuen Ordner namens "Fakes".
Fügen Sie eine Klassendatei
FakeFileService.csim Ordner "Fakes" hinzu:using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Windows.Storage; using WinUINotes.Services; namespace WinUINotes.Tests.Fakes { internal class FakeFileService : IFileService { private Dictionary<string, string> fileStorage = []; public async Task CreateOrUpdateFileAsync(string filename, string contents) { if (fileStorage.ContainsKey(filename)) { fileStorage[filename] = contents; } else { fileStorage.Add(filename, contents); } await Task.Delay(10); // Simulate some async work } public async Task DeleteFileAsync(string filename) { if (fileStorage.ContainsKey(filename)) { fileStorage.Remove(filename); } await Task.Delay(10); // Simulate some async work } public bool FileExists(string filename) { if (string.IsNullOrEmpty(filename)) { throw new ArgumentException("Filename cannot be null or empty", nameof(filename)); } if (fileStorage.ContainsKey(filename)) { return true; } return false; } public IStorageFolder GetLocalFolder() { return new FakeStorageFolder(fileStorage); } public async Task<IReadOnlyList<IStorageItem>> GetStorageItemsAsync() { await Task.Delay(10); return GetStorageItemsInternal(); } public async Task<IReadOnlyList<IStorageItem>> GetStorageItemsAsync(IStorageFolder storageFolder) { await Task.Delay(10); return GetStorageItemsInternal(); } private IReadOnlyList<IStorageItem> GetStorageItemsInternal() { return fileStorage.Keys.Select(filename => CreateFakeStorageItem(filename)).ToList(); } private IStorageItem CreateFakeStorageItem(string filename) { return new FakeStorageFile(filename); } public async Task<string> GetTextFromFileAsync(IStorageFile file) { await Task.Delay(10); if (fileStorage.ContainsKey(file.Name)) { return fileStorage[file.Name]; } return string.Empty; } } }Das
FakeFileServiceVerwendet ein Speicherwörterbuch (fileStorage), um Dateivorgänge zu simulieren, ohne das tatsächliche Dateisystem zu berühren. Zu den wichtigsten Features gehören:-
Asynchrone Simulation: Verwendet
Task.Delay(10), um echte asynchrone Dateivorgänge nachzuahmen - Überprüfung: Löst Ausnahmen für ungültige Eingaben aus, genau wie die echte Implementierung
-
Integration mit simulierten Speicherklassen: Gibt
FakeStorageFolder- undFakeStorageFile-Instanzen zurück, die zusammenarbeiten, um die Windows Storage-API zu simulieren
-
Asynchrone Simulation: Verwendet
Fügen Sie
FakeStorageFolder.cshinzu:using System; using System.Collections.Generic; using System.Runtime.InteropServices.WindowsRuntime; using Windows.Foundation; using Windows.Storage; using Windows.Storage.FileProperties; using Windows.Storage.Search; namespace WinUINotes.Tests.Fakes { internal class FakeStorageFolder : IStorageFolder { private string name; private Dictionary<string, string> fileStorage = []; public FakeStorageFolder(Dictionary<string, string> files) { fileStorage = files; } public FileAttributes Attributes => throw new NotImplementedException(); public DateTimeOffset DateCreated => throw new NotImplementedException(); public string Name => name; public string Path => throw new NotImplementedException(); public IAsyncOperation<StorageFile> CreateFileAsync(string desiredName) { throw new NotImplementedException(); } public IAsyncOperation<StorageFile> CreateFileAsync(string desiredName, CreationCollisionOption options) { throw new NotImplementedException(); } public IAsyncOperation<StorageFolder> CreateFolderAsync(string desiredName) { throw new NotImplementedException(); } // Only partial implementation shown for brevity ... } }Der
FakeStorageFolderDateispeicher-Verzeichnis wird im Konstruktor aufgenommen, sodass es im gleichen In-Memory-Dateisystem wieFakeFileServicefunktioniert. Die meisten Schnittstellenmitglieder werfenNotImplementedException, da nur die Eigenschaften und Methoden implementiert werden müssen, die tatsächlich von den Tests verwendet werden.Sie können die vollständige Implementierung
FakeStorageFolderim GitHub-Code-Repository für dieses Lernprogramm anzeigen.Fügen Sie
FakeStorageFile.cshinzu:using System; using System.IO; using System.Runtime.InteropServices.WindowsRuntime; using Windows.Foundation; using Windows.Storage; using Windows.Storage.FileProperties; using Windows.Storage.Streams; namespace WinUINotes.Tests.Fakes { public class FakeStorageFile : IStorageFile { private string name; public FakeStorageFile(string name) { this.name = name; } public string ContentType => throw new NotImplementedException(); public string FileType => throw new NotImplementedException(); public FileAttributes Attributes => throw new NotImplementedException(); public DateTimeOffset DateCreated => throw new NotImplementedException(); public string Name => name; public string Path => throw new NotImplementedException(); public IAsyncOperation<StorageFile> CopyAsync(IStorageFolder destinationFolder) { throw new NotImplementedException(); } public IAsyncOperation<StorageFile> CopyAsync(IStorageFolder destinationFolder, string desiredNewName) { throw new NotImplementedException(); } public IAsyncOperation<StorageFile> CopyAsync(IStorageFolder destinationFolder, string desiredNewName, NameCollisionOption option) { throw new NotImplementedException(); } public IAsyncAction CopyAndReplaceAsync(IStorageFile fileToReplace) { throw new NotImplementedException(); } // Only partial implementation shown for brevity ... } }Das
FakeStorageFilestellt einzelne Dateien im gefälschten Speichersystem dar. Er speichert den Dateinamen und stellt die minimale Implementierung bereit, die für die Tests erforderlich ist. WieFakeStorageFolderimplementiert sie nur die Member, die tatsächlich vom getesteten Code verwendet werden.Sie können die vollständige Implementierung
FakeStorageFolderim GitHub-Code-Repository für dieses Lernprogramm anzeigen.
Weitere Informationen finden Sie in den Dokumenten:
Schreiben eines einfachen Komponententests
Benennen Sie
UnitTest1.csinNoteTests.csum und aktualisieren Sie es.using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using WinUINotes.Tests.Fakes; namespace WinUINotes.Tests { [TestClass] public partial class NoteTests { [TestMethod] public void TestCreateUnsavedNote() { var noteVm = new ViewModels.NoteViewModel(new FakeFileService()); Assert.IsNotNull(noteVm); Assert.IsTrue(noteVm.Date > DateTime.Now.AddHours(-1)); Assert.IsTrue(noteVm.Filename.EndsWith(".txt")); Assert.IsTrue(noteVm.Filename.StartsWith("notes")); noteVm.Text = "Sample Note"; Assert.AreEqual("Sample Note", noteVm.Text); noteVm.SaveCommand.Execute(null); Assert.AreEqual("Sample Note", noteVm.Text); } } }Dieser Test zeigt, wie der
NoteViewModelmithilfe desFakeFileServicegetestet werden kann. Der Test erstellt einen neuenNoteViewModelZustand, überprüft den Anfangszustand (Datum ist aktuell, Dateiname folgt dem erwarteten Muster), legt Text für die Notiz fest, führt den Speicherbefehl aus und bestätigt, dass der Text beibehalten wird. Da der gefälschte Dateidienst anstelle der echten Implementierung verwendet wird, wird der Test schnell ohne tatsächliche Datei-E/A ausgeführt und kann wiederholt ohne Nebenwirkungen ausgeführt werden.
Weitere Informationen finden Sie in den Dokumenten:
Ausführen der Tests
- Öffnen Sie das Fenster Test-Explorer in Visual Studio (Test>Test-Explorer).
- Wählen Sie "Alle Tests ausführen " aus, um den Komponententest auszuführen.
- Überprüfen Sie, ob der Test bestanden wurde.
Sie verfügen jetzt über eine testbare Architektur, in der Sie Ihre ViewModels und Dienste unabhängig von der Benutzeroberfläche testen können!
Zusammenfassung
In dieser Lernprogrammreihe haben Sie folgendes gelernt:
- Erstellen Sie ein separates Klassenbibliotheksprojekt (Busprojekt), um Ihre ViewModels und Dienste zu speichern, sodass Komponententests getrennt von der UI-Ebene aktiviert werden.
- Implementieren Sie das MVVM-Muster mit dem MVVM-Toolkit, indem Sie
ObservableObject,[ObservableProperty]-Attribute und[RelayCommand]verwenden, um Standardcode zu reduzieren. - Verwenden Sie Quellgeneratoren, um Benachrichtigungen und Befehlsimplementierungen für Eigenschaftenänderungen automatisch zu erstellen.
- Verwenden Sie
[NotifyCanExecuteChangedFor], um die Verfügbarkeit von Befehlen automatisch zu aktualisieren, wenn sich Eigenschaftswerte ändern. - Integrieren Sie die Abhängigkeitsinjektion mit
Microsoft.Extensions.DependencyInjectionmithilfe von ViewModels und Diensten, um deren Lebenszyklus zu verwalten. - Erstellen Sie eine
IFileServiceSchnittstelle und Implementierung, um Dateivorgänge auf eine überprüfbare Weise zu handhaben. - Konfigurieren Sie den DI-Container in
App.xaml.cs, und rufen Sie ViewModels vom Dienstanbieter auf Ihren Seiten ab. - Implementieren Sie
WeakReferenceMessenger, um die lose Kopplung zwischen Komponenten zu ermöglichen, sodass Seiten auf ViewModel-Ereignisse reagieren können, ohne direkte Verweise. - Erstellen Sie Nachrichtenklassen, die von
ValueChangedMessage<T>erben, um Daten zwischen Komponenten zu übertragen. - Erstellen Sie gefälschte Implementierungen von Abhängigkeiten zum Testen, ohne das eigentliche Dateisystem zu berühren.
- Schreiben sie Komponententests mithilfe von MSTest, um das ViewModel-Verhalten unabhängig von der UI-Ebene zu überprüfen.
Diese Architektur bietet eine solide Grundlage für die Erstellung von wartungsfähigen, testbaren WinUI-Anwendungen mit klarer Trennung von Bedenken zwischen ui-, Geschäftslogik- und Datenzugriffsebenen. Sie können den Code für dieses Lernprogramm aus dem GitHub-Repository herunterladen oder anzeigen.
Nächste Schritte
Nachdem Sie nun wissen, wie Sie MVVM mit dem MVVM-Toolkit und der Abhängigkeitsinjektion implementieren, können Sie erweiterte Themen erkunden:
- Advanced Messaging: Erkunden Sie zusätzliche Messagingmuster, einschließlich Anforderungs-/Antwortnachrichten und Nachrichtentoken für die selektive Nachrichtenverarbeitung.
- Überprüfung: Fügen Sie Ihren ViewModels Eingabeüberprüfungen mithilfe von Datenanmerkungen und den Überprüfungsfeatures des MVVM-Toolkits hinzu.
-
Asynchrone Befehle: Erfahren Sie mehr über die asynchrone Befehlsausführung, die Abbruchunterstützung und die Fortschrittsberichterstattung mit
AsyncRelayCommand. - Erweiterte Tests: Erkunden Sie erweiterte Testszenarien, einschließlich Testen der Nachrichtenverarbeitung, asynchroner Befehlsausführung und Eigenschaftenänderungsbenachrichtigungen.
-
Observable Collections: Verwenden Sie
ObservableCollection<T>effektiv und erkunden SieObservableRangeCollection<T>Massenvorgänge.
Verwandte Inhalte
Windows developer