Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Teraz, gdy modele i usługi ViewModels znajdują się w oddzielnej bibliotece klas, możesz łatwo tworzyć testy jednostkowe. Dodawanie projektów testów jednostkowych umożliwia sprawdzenie, czy modele i usługi ViewModels zachowują się zgodnie z oczekiwaniami bez polegania na warstwie interfejsu użytkownika lub testowaniu ręcznym. Testy jednostkowe można uruchamiać automatycznie w ramach przepływu pracy programowania, zapewniając, że kod pozostaje niezawodny i konserwowalny.
Tworzenie projektu testów jednostkowych
- Kliknij rozwiązanie prawym przyciskiem myszy w Eksploratorze rozwiązań.
- Wybierz pozycję Dodaj>nowy projekt....
- Wybierz szablon aplikacji WinUI Unit Test App i wybierz pozycję Dalej.
- Nadaj projektowi nazwę
WinUINotes.Testsi wybierz pozycję Utwórz.
Dodawanie odwołań do projektu
- Kliknij prawym przyciskiem myszy projekt WinUINotes.Tests i wybierz polecenie Dodaj>Odwołanie do projektu....
- Sprawdź projekt WinUINotes.Bus i wybierz przycisk OK.
Tworzenie fałszywych implementacji na potrzeby testowania
Na potrzeby testowania utwórz fałszywe implementacje klas usługi plików i pamięci, które nie zapisują do systemu plików. Fałszywe to lekkie implementacje, które symulują zachowanie rzeczywistych zależności na potrzeby testowania.
W projekcie WinUINotes.Tests utwórz nowy folder o nazwie Fakes.
Dodaj plik
FakeFileService.csklasy w folderze Fakes: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; } } }Funkcja
FakeFileServiceużywa słownika w pamięci (fileStorage) do symulowania operacji na plikach bez dotykania rzeczywistego systemu plików. Najważniejsze funkcje:-
Symulacja asynchroniczna: używa
Task.Delay(10)do naśladowania rzeczywistych operacji plików asynchronicznych - Walidacja: zgłasza wyjątki dla nieprawidłowych danych wejściowych, podobnie jak rzeczywista implementacja
-
Integracja z fałszywymi klasami magazynu: zwraca wystąpienia
FakeStorageFolderiFakeStorageFile, które pracują wspólnie nad symulacją interfejsu API Windows Storage.
-
Symulacja asynchroniczna: używa
Dodaj
FakeStorageFolder.cspolecenie :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 ... } }Obiekt
FakeStorageFolderprzyjmuje słownik przechowywania plików w swoim konstruktorze, co umożliwia pracę z tym samym systemem plików w pamięci, coFakeFileService. Większość elementów członkowskich interfejsu zgłaszaNotImplementedException, ponieważ konieczne jest zaimplementowanie jedynie tych właściwości i metod, które są wykorzystywane przez testy.Możesz wyświetlić pełną implementację
FakeStorageFolderw repozytorium kodu GitHub dla tego samouczka.Dodaj
FakeStorageFile.cspolecenie :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 ... } }FakeStorageFilereprezentuje pojedyncze pliki w fałszywym systemie przechowywania danych. Przechowuje nazwę pliku i zapewnia minimalną implementację wymaganą do testów. Podobnie jakFakeStorageFolder, implementuje tylko te członki, które są rzeczywiście używane przez testowany kod.Możesz wyświetlić pełną implementację
FakeStorageFolderw repozytorium kodu GitHub dla tego samouczka.
Dowiedz się więcej w dokumentacji:
Pisanie prostego testu jednostkowego
Zmień nazwę
UnitTest1.csnaNoteTests.csi zaktualizuj ją: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); } } }W tym teście pokazano, jak przeprowadzić test jednostkowy
NoteViewModelprzy użyciu elementuFakeFileService. Test tworzy nowyNoteViewModelelement, sprawdza jego stan początkowy (data jest świeża, nazwa pliku jest zgodna z oczekiwanym wzorcem), ustawia tekst w notatce, uruchamia polecenie zapisywania i potwierdza, że tekst zostaje zachowany. Ponieważ fałszywa usługa plików jest używana zamiast rzeczywistej implementacji, test jest uruchamiany szybko bez rzeczywistego we/wy pliku i może działać wielokrotnie bez skutków ubocznych.
Dowiedz się więcej w dokumentacji:
Uruchamianie testów
- Otwórz okno Eksplorator testów w programie Visual Studio (Eksplorator testów>).
- Wybierz pozycję Uruchom wszystkie testy , aby wykonać test jednostkowy.
- Sprawdź, czy test przebiegnie pomyślnie.
Masz teraz architekturę testową, w której można testować modele i usługi niezależnie od interfejsu użytkownika!
Podsumowanie
W tej serii samouczków przedstawiono sposób wykonywania następujących instrukcji:
- Utwórz oddzielny projekt biblioteki klas (projekt Bus) do przechowywania ViewModeli i usług, umożliwiając testowanie jednostkowe niezależnie od warstwy interfejsu użytkownika.
- Zaimplementuj wzorzec MVVM przy użyciu zestawu narzędzi MVVM, wykorzystując
ObservableObjectatrybuty,[ObservableProperty]i[RelayCommand], aby zredukować nadmiarowy kod. - Użyj generatorów źródłowych, aby automatycznie tworzyć powiadomienia o zmianie właściwości i implementacje poleceń.
- Użyj
[NotifyCanExecuteChangedFor]polecenia , aby automatycznie aktualizować dostępność poleceń po zmianie wartości właściwości. - Zintegruj wstrzykiwanie zależności za pomocą
Microsoft.Extensions.DependencyInjection, aby zarządzać cyklem życia ViewModeli i usług. - Tworzenie interfejsu
IFileServicei implementacji do obsługi operacji na plikach w możliwy do przetestowania sposób. - Skonfiguruj kontener DI w
App.xaml.csi pobierz ViewModel z dostawcy usług na swoich stronach. - Zaimplementuj element ,
WeakReferenceMessengeraby umożliwić luźne sprzężenie między składnikami, dzięki czemu strony mogą reagować na zdarzenia ViewModel bez bezpośrednich odwołań. - Utwórz klasy komunikatów dziedziczone z
ValueChangedMessage<T>w celu przenoszenia danych między składnikami. - Twórz fałszywe implementacje zależności na potrzeby testowania bez dotykania rzeczywistego systemu plików.
- Pisanie testów jednostkowych przy użyciu narzędzia MSTest w celu zweryfikowania zachowania modelu ViewModel niezależnie od warstwy interfejsu użytkownika.
Ta architektura zapewnia solidną podstawę do tworzenia stałych, testowalnych aplikacji WinUI z wyraźnym rozdzieleniem problemów między interfejsem użytkownika, logiką biznesową i warstwami dostępu do danych. Możesz pobrać lub wyświetlić kod tego samouczka z repozytorium GitHub.
Dalsze kroki
Teraz, gdy już wiesz, jak zaimplementować maszynę MVVM za pomocą zestawu narzędzi MVVM Toolkit i iniekcji zależności, możesz zapoznać się z bardziej zaawansowanymi tematami:
- Zaawansowane obsługa komunikatów: eksplorowanie dodatkowych wzorców obsługi komunikatów, w tym komunikatów żądań/odpowiedzi i tokenów komunikatów na potrzeby selektywnej obsługi komunikatów.
- Walidacja: dodaj walidację danych wejściowych do modelu ViewModels przy użyciu adnotacji danych i funkcji weryfikacji zestawu narzędzi MVVM Toolkit.
-
Polecenia asynchroniczne: dowiedz się więcej na temat asynchronicznego wykonywania poleceń, obsługi anulowania i raportowania postępu za pomocą polecenia
AsyncRelayCommand. - Testowanie zaawansowane: eksplorowanie bardziej zaawansowanych scenariuszy testowania, w tym testowanie obsługi komunikatów, asynchroniczne wykonywanie poleceń i powiadomienia o zmianie właściwości.
-
Obserwowalne kolekcje: efektywne używanie
ObservableCollection<T>oraz analizaObservableRangeCollection<T>dla operacji zbiorczych.
Treści powiązane
Windows developer