Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Agora que seus ViewModels e serviços estão em uma biblioteca de classes separada, você pode criar facilmente testes de unidade. Adicionar projetos de teste de unidade permite verificar se seus ViewModels e serviços se comportam conforme o esperado sem depender da camada de interface do usuário ou de testes manuais. Você pode executar testes de unidade automaticamente como parte do fluxo de trabalho de desenvolvimento, garantindo que seu código permaneça confiável e sustentável.
Criar um projeto de teste de unidade
- Clique com o botão direito do rato na solução no Solution Explorer.
- Selecione Adicionar>novo projeto....
- Escolha o modelo WinUI Unit Test App e selecione Next.
- Nomeie o projeto
WinUINotes.Testse selecione Criar.
Adicionar referências do projeto
- Clique com o botão direito do mouse no projeto WinUINotes.Tests e selecione Adicionar>referência do projeto....
- Verifique o projeto WinUINotes.Bus e selecione OK.
Crie implementações falsas para testes
Para testes, crie implementações falsas do serviço de arquivos e classes de armazenamento que realmente não gravam no disco. Fakes são implementações leves que simulam o comportamento de dependências reais para fins de teste.
No projeto WinUINotes.Tests , crie uma nova pasta chamada Fakes.
Adicione um arquivo
FakeFileService.csde classe na pasta 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; } } }O
FakeFileServiceusa um dicionário na memória (fileStorage) para simular operações de arquivo sem tocar no sistema de arquivos real. As principais funcionalidades incluem:-
Simulação assíncrona: usa
Task.Delay(10)para imitar operações de arquivo assíncronas reais - Validação: lança exceções para entradas inválidas, assim como a implementação real
-
Integração com classes de armazenamento falsas: retorna
FakeStorageFoldereFakeStorageFileinstâncias que trabalham juntas para simular a API de armazenamento do Windows
-
Simulação assíncrona: usa
Adicionar
FakeStorageFolder.cs: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 ... } }O
FakeStorageFolderusa o dicionário de armazenamento de arquivos no seu construtor, permitindo que ele trabalhe com o mesmo sistema de arquivos na memória queFakeFileService. A maioria dos membros da interface lança,NotImplementedExceptionuma vez que apenas as propriedades e métodos realmente usados pelos testes precisam ser implementados.Você pode visualizar a implementação completa de
FakeStorageFolderno repositório de código do GitHub para este tutorial.Adicionar
FakeStorageFile.cs: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 ... } }O
FakeStorageFilerepresenta arquivos individuais no sistema de armazenamento falso. Ele armazena o nome do arquivo e fornece a implementação mínima necessária para os testes. ComoFakeStorageFolder, ele só implementa os membros que são realmente usados pelo código que está sendo testado.Você pode visualizar a implementação completa de
FakeStorageFolderno repositório de código do GitHub para este tutorial.
Saiba mais nos documentos:
Escrever um teste de unidade simples
Renomeie
UnitTest1.csparaNoteTests.cse atualize-o: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); } } }Este teste mostra como testar a unidade usando o
NoteViewModelFakeFileService. O teste cria um novoNoteViewModel, verifica seu estado inicial (a data é recente, o nome do arquivo segue o padrão esperado), define o texto na nota, executa o comando salvar e confirma que o texto persiste. Como o serviço de arquivos falso é usado em vez da implementação real, o teste é executado rapidamente sem qualquer E/S de arquivo real e pode ser executado repetidamente sem efeitos colaterais.
Saiba mais nos documentos:
Executar os testes
- Abra a janela Test Explorer no Visual Studio (Test>Test Explorer).
- Selecione Executar todos os testes para executar o teste de unidade.
- Verifique se o teste foi aprovado.
Agora você tem uma arquitetura testável onde pode testar seus ViewModels e serviços independentemente da interface do usuário!
Resumo
Nesta série de tutoriais, você aprendeu como:
- Crie um projeto de biblioteca de classes separado (projeto Bus) para armazenar seus ViewModels e serviços, permitindo o teste de unidade separado da camada da interface do usuário.
- Implemente o padrão MVVM usando o MVVM Toolkit, aproveitando
ObservableObject,[ObservableProperty]atributos e[RelayCommand]para reduzir o código repetitivo. - Use geradores de código-fonte para criar automaticamente notificações de alteração de propriedade e implementações de comando.
- Use
[NotifyCanExecuteChangedFor]para atualizar automaticamente a disponibilidade do comando quando os valores de propriedade forem alterados. - Integre a injeção de dependência usando
Microsoft.Extensions.DependencyInjectionpara gerenciar o ciclo de vida de ViewModels e serviços. - Crie uma interface e implementação
IFileServicepara lidar com operações de arquivo de forma testável. - Configurar o contêiner DI em
App.xaml.cse recuperar os ViewModels do provedor de serviços nas suas páginas. - Implemente o
WeakReferenceMessengerpara permitir o acoplamento solto entre componentes, permitindo que as páginas respondam a eventos do ViewModel sem referências diretas. - Crie classes de mensagem que herdem de
ValueChangedMessage<T>para transportar dados entre componentes. - Crie implementações falsas de dependências para teste sem tocar no sistema de arquivos real.
- Escreva testes de unidade usando MSTest para verificar o comportamento ViewModel independentemente da camada da interface do usuário.
Essa arquitetura fornece uma base sólida para a criação de aplicativos WinUI fáceis de manter e testáveis, com separação clara de preocupações entre a interface do usuário, a lógica de negócios e as camadas de acesso a dados. Você pode baixar ou visualizar o código para este tutorial no repositório GitHub.
Próximos passos
Agora que você entende como implementar o MVVM com o MVVM Toolkit e a injeção de dependência, você pode explorar tópicos mais avançados:
- Mensagens avançadas: explore padrões de mensagens adicionais, incluindo mensagens de solicitação/resposta e tokens de mensagens para tratamento seletivo de mensagens.
- Validação: adicione a validação de entrada aos seus ViewModels usando anotações de dados e os recursos de validação do MVVM Toolkit.
-
Comandos assíncronos: saiba mais sobre a execução assíncrona de comandos, suporte a cancelamento e relatórios de progresso com
AsyncRelayCommando . - Testes avançados: explore cenários de teste mais avançados, incluindo o tratamento de mensagens de teste, a execução assíncrona de comandos e notificações de alteração de propriedade.
-
Coleções observáveis: use
ObservableCollection<T>de forma eficaz e exploreObservableRangeCollection<T>para operações em massa.
Conteúdo relacionado
Windows developer