Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Agora que seus ViewModels e serviços estão em uma biblioteca de classes separada, você pode facilmente criar testes de unidade. A adição de 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 do teste manual. 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 mantenedível.
Criar um projeto de teste de unidade
- Clique com o botão direito do mouse na solução no Gerenciador de Soluções.
- Selecione Adicionar>Novo Projeto....
- Escolha o modelo de Aplicativo de Teste de Unidade do WinUI e selecione Avançar.
- Nomeie o projeto
WinUINotes.Testse selecione Criar.
Adicionar referências de 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.
Criar implementações falsas para teste
Para testar, crie implementações falsas do serviço de arquivos e das classes de armazenamento que realmente não gravam em disco. As falsificações 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 de classe
FakeFileService.csna 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. Os principais recursos incluem:-
Simulação assíncrona: usa
Task.Delay(10)para imitar operações reais de arquivo assíncrono - Validação: gera exceções para entradas inválidas, assim como a implementação real
-
Integração com classes de armazenamento falsas: retorna
FakeStorageFoldereFakeStorageFileinstâncias que funcionam em conjunto 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 ... } }FakeStorageFolderrecebe o dicionário de armazenamento de arquivos em seu construtor, permitindo que funcione com o mesmo sistema de arquivos em memória queFakeFileService. A maioria dos membros da interface lançaNotImplementedException, pois apenas as propriedades e os métodos realmente usados pelos testes precisam ser implementados.Você pode ver 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. Assim comoFakeStorageFolder, ele implementa apenas os membros que são realmente usados pelo código que está sendo testado.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-o
UnitTest1.csNoteTests.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 fazer o teste unitário do
NoteViewModelusando oFakeFileService. 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 save e confirma se o texto persiste. Como o serviço de arquivo falso é usado em vez da implementação real, o teste é executado rapidamente sem nenhuma E/S de arquivo real e pode ser executado repetidamente sem efeitos colaterais.
Saiba mais nos documentos:
Executar os testes
- Abra a janela do Gerenciador de Testes no Visual Studio (Gerenciador de Testes>).
- Selecione Executar Todos os Testes para executar o teste de unidade.
- Verifique se o teste foi aprovado.
Agora você tem uma arquitetura testável em que pode testar seus ViewModels e serviços independentemente da interface do usuário!
Resumo
Nesta série de tutoriais, você aprendeu a:
- Crie um projeto de biblioteca de classes separado (projeto Bus) para armazenar seus ViewModels e serviços, permitindo que os testes de unidade sejam realizados de forma independente da camada de interface do usuário.
- Implemente o padrão MVVM usando o Kit de Ferramentas MVVM, aproveitando
ObservableObject,[ObservableProperty]atributos e[RelayCommand]reduzindo o código clichê. - Use geradores de origem 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 da 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
IFileServiceinterface e implementação para lidar com operações de arquivo de maneira testável. - Configure o contêiner de DI em
App.xaml.cse recupere os ViewModels do provedor de serviços em suas páginas. - Implemente o
WeakReferenceMessengeracoplamento flexível entre componentes, permitindo que as páginas respondam a eventos 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 do ViewModel de forma independente da camada de UI.
Essa arquitetura fornece uma base sólida para a criação de aplicativos WinUI compatíveis e testáveis com clara separação 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 exibir o código deste tutorial no repositório do GitHub.
Próximas etapas
Agora que você entende como implementar o MVVM com o Kit de Ferramentas MVVM 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 mensagem para tratamento seletivo de mensagens.
- Validação: adicione validação de entrada aos ViewModels usando anotações de dados e os recursos de validação do Kit de Ferramentas do MVVM.
-
Comandos assíncronos: saiba mais sobre execução de comando assíncrono, suporte a cancelamento e relatórios de progresso com
AsyncRelayCommand. - Teste Avançado: explore cenários de teste mais avançados, incluindo teste de tratamento de mensagens, execução de comando assíncrono e notificações de alteração de propriedade.
-
Coleções observáveis: use
ObservableCollection<T>efetivamente e exploreObservableRangeCollection<T>para operações em massa.
Conteúdo relacionado
Windows developer