Exercício: Desenvolver testes de unidade usando ferramentas do GitHub Copilot
O GitHub Copilot pode ajudar você a escrever testes de unidade para seu código. Há várias maneiras de usar o GitHub Copilot para gerar testes de unidade:
- Gerar casos de teste: Você pode usar o GitHub Copilot para gerar casos de teste para seu código. O Copilot pode sugerir casos de teste com base no código que você escreveu. Em seguida, você pode usar esses casos de teste para criar testes de unidade para seu código.
- Gerar métodos de teste: O Copilot também pode gerar métodos de teste para seu código. Você pode usar esses métodos de teste para criar testes de unidade para seu código.
- Gerar asserções de teste: O Copilot pode sugerir asserções que você pode usar em seus testes de unidade. Essas asserções podem ajudar você a verificar o comportamento do código.
- Gerar simulações de teste: O Copilot pode gerar objetos de simulação que você pode usar em seus testes de unidade. Esses objetos de simulação podem ajudar você a isolar o código que você está testando de suas dependências.
- Gerar dados de teste: O Copilot pode gerar dados de teste que você pode usar em seus testes de unidade. Esses dados de teste podem ajudar você a testar seu código com entradas diferentes.
- Gerar código de configuração do teste: O Copilot pode gerar o código de configuração para seus testes de unidade. Esse código pode ajudar você a configurar o ambiente de teste antes de executar seus testes.
- Gerar código de desinstalação do teste: O Copilot pode gerar o código de desinstalação de seus testes de unidade. Esse código pode ajudar você a limpar o ambiente de teste depois de executar seus testes.
Sua solução existente inclui um projeto de teste de unidade chamado UnitTests. Este projeto já contém testes de unidade que abrangem parcialmente as classes de serviço no projeto ApplicationCore.
Neste exercício, você vai usar o GitHub Copilot para realizar as seguintes tarefas:
Examinar a abordagem de teste de unidade implementada pelo projeto UnitTests.
Estender o projeto UnitTests para começar a testar as classes de acesso aos dados no projeto
Library.Infrastructure.
Examinar a abordagem de teste de unidade implementada pelo projeto UnitTests
Sua base de código existente inclui um projeto UnitTests que implementa a seguinte estrutura de pastas:
- UnitTests\
- ApplicationCore\
- LoanService\
ExtendLoan.csReturnLoan.cs
- PatronService\
RenewMembership.cs
- LoanService\
- LoanFactory.cs
- PatronFactory.cs
- ApplicationCore\
Essa estrutura espelha e dá suporte à parte Services do projeto ApplicationCore.
- ApplicationCore\
- Services\
- LoanService.cs: Contém os métodos
ExtendLoaneReturnLoan. - PatronService.cs: Contém o método
RenewMembership.
- LoanService.cs: Contém os métodos
- Services\
Nesta seção do exercício, você usará o GitHub Copilot para examinar a abordagem de teste de unidade implementada pelo projeto UnitTests.
Use as seguintes etapas para concluir esta seção do exercício:
Abra o modo de exibição de chat.
Adicione os seguintes arquivos ao contexto de chat:
LoanFactory.cs,PatronFactory.cs,ExtendLoan.cs,ReturnLoan.cs,RenewMembership.cs,LoanService.csePatronService.cs.Os arquivos estão localizados nas pastas
tests/UnitTests,tests/UnitTests/ApplicationCore/LoanService,tests/UnitTests/ApplicationCore/PatronServiceesrc/Library.ApplicationCore/Services.Digite a seguinte solicitação:
@workspace Explain the approach to unit testing that's been implemented in this workspace.Essa solicitação pede ao GitHub Copilot que explique a abordagem para o teste de unidade no contexto do workspace. Vários arquivos são incluídos na solicitação para fornecer contexto para a resposta.
Reserve um minuto para examinar a resposta do GitHub Copilot.
Você deve ver uma explicação semelhante à seguinte descrição:
- Simular dependências: Os testes usam
NSubstitutepara criar implementações simuladas de interfaces. - Organização de teste: Os testes são organizados em arquivos separados com base nos métodos que estão sendo testados. Por exemplo, métodos
ExtendLoaneReturnLoansão testados em arquivos separados na pastaLoanService. - Asserções: As asserções são usadas para verificar o resultado esperado de cada teste.
- Cenários de teste: Os testes abrangem vários cenários para cada método, como o retorno de status diferentes com base na entrada.
- Isolamento: Cada teste é isolado de outros para evitar efeitos colaterais.
- Métodos de fábrica: Os métodos de fábrica são usados para criar dados de teste consistentemente.
- Simular dependências: Os testes usam
Digite a seguinte solicitação:
@workspace What are the benefits of this approach to unit testing?Reserve um minuto para examinar a resposta do GitHub Copilot.
Você deverá ver uma explicação que identifica uma lista de benefícios semelhante à seguinte lista:
- Isolamento de dependências: Usar simulações isola a unidade de trabalho de suas dependências.
- Repetibilidade e consistência: Os métodos de fábrica fornecem uma maneira consistente de criar dados de teste.
- Legibilidade e manutenção: Os métodos de teste descritivos e a disposição clara das etapas de teste melhoram a legibilidade dos testes.
- Cobertura abrangente: Testar vários cenários garante que o código seja robusto e lide com diferentes casos de borda.
- Separação de preocupações: A separação da criação de dados de teste da lógica de teste em si mantém os testes limpos e focados no comportamento que está sendo testado.
- Comentários imediatos: A execução de testes de unidade fornece comentários imediatos sobre a correção do código.
Adicione os seguintes arquivos ao contexto de chat:
ExtendLoan.cs,ReturnLoan.cs,RenewMembership.cs,LoanFactory.cs,PatronFactory.cs,LoanService.csePatronService.cs.Digite a seguinte solicitação:
@workspace How can I extend the `UnitTests` project to begin testing methods in the `Library.Infrastructure` project? Provide a process overview.Essa solicitação solicita que o GitHub Copilot forneça uma visão geral do processo para estender o projeto
UnitTestspara começar a testar métodos no projetoLibrary.Infrastructure. Vários arquivos são incluídos na solicitação para fornecer contexto para a resposta.Reserve um minuto para examinar a resposta do GitHub Copilot.
Você deve ver uma explicação semelhante à seguinte descrição:
1. Add Project Reference: - Open the `UnitTests.csproj` file located at `tests/UnitTests/UnitTests.csproj`. - Add a reference to the `Library.Infrastructure` project. 2. Identify methods to test: - Identify the methods in the `Library.Infrastructure` project that need to be tested. For example, if you want to test the `LoanService` class, identify the methods in the `LoanService` class that need to be tested. 3. Create Test Classes: - Create new test classes in the `tests/UnitTests` directory to test the methods in the `Library.Infrastructure` project. For example, if you want to test `LoanService`, create a file named `LoanServiceTests.cs`. 4. Write Unit Tests: - In the newly created test classes, write unit tests for the methods in the `Library.Infrastructure` project. Use the xUnit framework for writing tests and NSubstitute for mocking dependencies. 5. Run Tests: - Use Visual Studio Code's integrated terminal or the Test Explorer to run the tests. - Ensure that the tests are discovered and executed correctly.
Estender o projeto UnitTests para começar a testar as classes de acesso aos dados
Nesta seção do exercício, você usará o GitHub Copilot para criar testes de unidade para o projeto Library.Infrastructure.
O projeto Library.Infrastructure contém classes de acesso aos dados que interagem com o sistema de arquivos para carregar e salvar dados. O projeto inclui as seguintes classes:
- JsonData: Uma classe que carrega e salva dados JSON.
- JsonLoanRepository: Uma classe que implementa a interface ILoanRepository e usa a classe JsonData para carregar e salvar dados de empréstimo.
- JsonPatronRepository: Uma classe que implementa a interface IPatronRepository e usa a classe JsonData para carregar e salvar dados de leitores.
Você começará escrevendo testes de unidade para a classe JsonLoanRepository.
Use as seguintes etapas para concluir esta seção do exercício:
Adicione os seguintes arquivos ao contexto de chat:
UnitTests.csproj.Insira a seguinte solicitação no modo de exibição de chat:
@workspace Explain how to add a reference to the Library.Infrastructure project inside `UnitTests.csproj`.Essa solicitação pede ao GitHub Copilot que explique como adicionar uma referência ao projeto
Library.Infrastructuredentro do arquivoUnitTests.csproj.Use a resposta do GitHub Copilot para atualizar o arquivo UnitTests.csproj.
O arquivo UnitTests.csproj atualizado deve ser semelhante ao seguinte código XML:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> <IsPackable>false</IsPackable> <IsTestProject>true</IsTestProject> </PropertyGroup> <ItemGroup> <PackageReference Include="coverlet.collector" Version="6.0.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" /> <PackageReference Include="NSubstitute" Version="5.1.0" /> <PackageReference Include="xunit" Version="2.5.3" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" /> </ItemGroup> <ItemGroup> <Using Include="Xunit" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\..\src\Library.ApplicationCore\Library.ApplicationCore.csproj" /> <ProjectReference Include="..\..\src\Library.Infrastructure\Library.Infrastructure.csproj" /> </ItemGroup> </Project>Abra o arquivo
JsonLoanRepository.cs.JsonLoanRepository.csestá localizado na pastasrc/Library.Infrastructure/Data/.Reserve um minuto para examinar o arquivo
JsonLoanRepository.cs.using Library.ApplicationCore; using Library.ApplicationCore.Entities; namespace Library.Infrastructure.Data; public class JsonLoanRepository : ILoanRepository { private readonly JsonData _jsonData; public JsonLoanRepository(JsonData jsonData) { _jsonData = jsonData; } public async Task<Loan?> GetLoan(int id) { await _jsonData.EnsureDataLoaded(); foreach (Loan loan in _jsonData.Loans!) { if (loan.Id == id) { Loan populated = _jsonData.GetPopulatedLoan(loan); return populated; } } return null; } public async Task UpdateLoan(Loan loan) { Loan? existingLoan = null; foreach (Loan l in _jsonData.Loans!) { if (l.Id == loan.Id) { existingLoan = l; break; } } if (existingLoan != null) { existingLoan.BookItemId = loan.BookItemId; existingLoan.PatronId = loan.PatronId; existingLoan.LoanDate = loan.LoanDate; existingLoan.DueDate = loan.DueDate; existingLoan.ReturnDate = loan.ReturnDate; await _jsonData.SaveLoans(_jsonData.Loans!); await _jsonData.LoadData(); } } }Observe os seguintes detalhes sobre a classe
JsonLoanRepository:- A classe
JsonLoanRepositorycontém dois métodos:GetLoaneUpdateLoan. - A classe
JsonLoanRepositoryusa um objetoJsonDatapara carregar e salvar dados de empréstimo.
Você começará escrevendo testes de unidade para o método
GetLoan.- A classe
Crie a estrutura de pastas a seguir no projeto
UnitTests.- Infrastructure\
- JsonLoanRepository\
Essa estrutura de pasta espelha a abordagem usada para os testes de unidade
Library.ApplicationCore.- Infrastructure\
Crie um arquivo de classe chamado
GetLoanna pastaJsonLoanRepository.Reserve um minuto para considerar os requisitos de construtor de campo e classe para os testes de unidade
GetLoan.O método
JsonLoanRepository.GetLoanrecebe um parâmetro de ID de empréstimo quando é chamado. O método usa_jsonData.EnsureDataLoadedpara obter os dados JSON mais recentes e_jsonData.Loanspara procurar um empréstimo correspondente. Se o método encontrar uma ID de empréstimo correspondente, ele retornará um objeto de empréstimo preenchido (populated). Se o método não conseguir encontrar uma ID de empréstimo correspondente, ele retornaránull.Para os testes de unidade GetLoan:
Você pode usar um objeto de repositório de empréstimo simulado (
_mockLoanRepository) para ajudar a testar o caso em que uma ID correspondente é encontrada. Carregue a simulação com a ID que você deseja encontrar. A classeReturnLoanTestdemonstra como simular a interfaceILoanRepositorye criar uma instância de um objeto de repositório de empréstimo simulado.Você pode usar um objeto de repositório de empréstimo não simulado (
_jsonLoanRepository) para testar o caso em que nenhuma ID correspondente é encontrada. Basta especificar uma ID de empréstimo que você sabe que não está no arquivo (qualquer coisa acima de 100 deve funcionar).Você precisará de um objeto
JsonDatapara criar um objetoJsonLoanRepositorynão simulado. Como o projetoUnitTestsnão tem acesso ao objetoJsonDatacriado pelo projetoConsoleApp, você precisará criar um usando a interfaceIConfiguration.
Adicione os seguintes arquivos ao contexto de chat:
JsonLoanRepository.cs,ReturnLoan.cs,LoanService.cs,LoanFactory.cseJsonData.cs.Digite a seguinte solicitação:
@workspace Create fields and a class constructor for the `GetLoan.cs` file. The class will be used to create unit tests for the GetLoan method in the `JsonLoanRepository.cs` file. Create the following private readonly fields: `_mockLoanRepository`, `_jsonLoanRepository`, `_configuration`, and `_jsonData`. Instantiate the fields in the `GetLoanTest` constructor. Use `ConfigurationBuilder` to create a `_configuration` object that can be used to instantiate the JsonData object.Essa solicitação pede ao GitHub Copilot que sugira campos e um construtor de classe.
Reserve um minuto para examinar a resposta do GitHub Copilot.
Você deve ver uma sugestão de código semelhante ao seguinte snippet de código:
using NSubstitute; using Library.ApplicationCore; using Library.ApplicationCore.Entities; using Library.ApplicationCore.Interfaces; using Library.Infrastructure.Data; using Microsoft.Extensions.Configuration; namespace UnitTests.Infrastructure.JsonLoanRepository; public class GetLoanTest { private readonly ILoanRepository _mockLoanRepository; private readonly JsonLoanRepository _jsonLoanRepository; private readonly IConfiguration _configuration; private readonly JsonData _jsonData; public GetLoanTest() { _mockLoanRepository = Substitute.For<ILoanRepository>(); _configuration = new ConfigurationBuilder() .AddJsonFile("appsettings.json") .Build(); _jsonData = new JsonData(_configuration); _jsonLoanRepository = new JsonLoanRepository(_jsonData); } // Add test methods here }Use a sugestão de código fornecida pelo GitHub Copilot para atualizar
GetLoan.cs.Observe os seguintes problemas:
Há um conflito entre o namespace e o uso de
JsonLoanRepositoryno código. Você deve atualizar o namespace em GetLoans.cs para seguir o padrão usado nos arquivosReturnLoan.cseRenewMembership.cs.Se
ILoanRepositorynão for reconhecido em seu código, talvez seja necessário adicionar uma diretivausingparaLibrary.ApplicationCoreno topo do arquivo.Se o objeto
_configurationnão for instanciado corretamente, talvez seja necessário atualizar a linha de código que contémConfigurationBuilder. Você pode simplificar o código para usar_configuration = new ConfigurationBuilder().Build();.Se
using Library.ApplicationCore.Interfacesfor sugerido pelo GitHub Copilot, você pode excluí-lo do topo do arquivo.
Atualize o arquivo
GetLoan.cspara que corresponda ao seguinte snippet de código:using NSubstitute; using Library.ApplicationCore; using Library.ApplicationCore.Entities; using Library.Infrastructure.Data; using Microsoft.Extensions.Configuration; namespace UnitTests.Infrastructure.JsonLoanRepositoryTests; public class GetLoanTest { private readonly ILoanRepository _mockLoanRepository; private readonly JsonLoanRepository _jsonLoanRepository; private readonly IConfiguration _configuration; private readonly JsonData _jsonData; public GetLoanTest() { _mockLoanRepository = Substitute.For<ILoanRepository>(); _configuration = new ConfigurationBuilder().Build(); _jsonData = new JsonData(_configuration); _jsonLoanRepository = new JsonLoanRepository(_jsonData); } }Adicione os seguintes arquivos ao contexto de chat:
JsonLoanRepository.cs,ReturnLoan.cs,LoanService.cs,LoanFactory.cs,JsonData.cseLoans.json.Selecione o conteúdo do arquivo
GetLoan.cse insira a seguinte solicitação no modo de exibição de chat:@workspace Update the selection to include a unit test for the `JsonLoanRepository.GetLoan` method. The unit test should test the case where a loan ID is found in the data. Use `_mockLoanRepository` to arrange the expected return loan. Use `_jsonLoanRepository` to return an actual loan. Asserts should verify that the return loan ID matches the expected loan ID. Use a loan ID that exists in the `Loans.json` file.Essa solicitação pede ao GitHub Copilot que sugira um teste de unidade para o método
JsonLoanRepository.GetLoan. O teste de unidade deve testar o caso em que uma ID de empréstimo é encontrada nos dados. O teste deve usar_mockLoanRepositorypara organizar o empréstimo de retorno esperado,_jsonLoanRepositorypara retornar um empréstimo real, e afirma verificar se a ID do empréstimo de retorno corresponde à ID de empréstimo esperada. A ID do empréstimo deve existir no arquivoLoans.json.Reserve um minuto para examinar a resposta do GitHub Copilot.
Você deve ver uma sugestão de código semelhante ao seguinte snippet de código:
using NSubstitute; using Library.ApplicationCore; using Library.ApplicationCore.Entities; using Library.Infrastructure.Data; using Microsoft.Extensions.Configuration; using Xunit; namespace UnitTests.Infrastructure.JsonLoanRepositoryTests; public class GetLoanTest { private readonly ILoanRepository _mockLoanRepository; private readonly JsonLoanRepository _jsonLoanRepository; private readonly IConfiguration _configuration; private readonly JsonData _jsonData; public GetLoanTest() { _mockLoanRepository = Substitute.For<ILoanRepository>(); _configuration = new ConfigurationBuilder().Build(); _jsonData = new JsonData(_configuration); _jsonLoanRepository = new JsonLoanRepository(_jsonData); } [Fact(DisplayName = "JsonLoanRepository.GetLoan: Returns loan when loan ID is found")] public async Task GetLoan_ReturnsLoanWhenLoanIdIsFound() { // Arrange var loanId = 1; // Use a loan ID that exists in the Loans.json file var expectedLoan = new Loan { Id = loanId, BookItemId = 101, PatronId = 202, LoanDate = DateTime.Now, DueDate = DateTime.Now.AddDays(14) }; _mockLoanRepository.GetLoan(loanId).Returns(expectedLoan); await _jsonData.EnsureDataLoaded(); // Ensure data is loaded // Act var actualLoan = await _jsonLoanRepository.GetLoan(loanId); // Assert Assert.NotNull(actualLoan); Assert.Equal(expectedLoan.Id, actualLoan?.Id); } }Use a sugestão de código fornecida pelo GitHub Copilot para atualizar
GetLoan.cs.O método
JsonLoanRepository.GetLoanchama_jsonData.EnsureDataLoadedpara garantir que os dados JSON sejam carregados. Você pode excluir a linha de código que chama_jsonData.EnsureDataLoadedno método de teste se ela estiver incluída.Se a classe
Loannão for reconhecida no seu código, certifique-se de ter uma instruçãousing Library.ApplicationCore.Entitiesno topo do arquivo GetLoan.cs. A classeLoanestá no namespaceLibrary.ApplicationCore.Entities.Crie a solução
AccelerateDevGitHubCopilotpara garantir que não haja nenhum erro.Use o recurso de preenchimento automático do GitHub Copilot para criar um teste para o caso em que a ID do empréstimo não for encontrada.
Crie uma linha em branco após o método
GetLoan_ReturnsLoanWhenLoanIdIsFound.Aceite as sugestões de preenchimento automático para criar um novo método de teste.
Reserve um minuto para examinar a resposta do GitHub Copilot.
O recurso de preenchimento automático do GitHub Copilot provavelmente simulará um empréstimo esperado, mesmo se não for necessário. Você pode excluir o código que simula um empréstimo esperado, mas precisa de uma ID de empréstimo que não exista no arquivo
Loans.json.Você deve ver uma sugestão de código semelhante a um dos seguintes snippets de código:
[Fact(DisplayName = "JsonLoanRepository.GetLoan: Returns null when loan ID is not found")] public async Task GetLoan_ReturnsNullWhenLoanIdIsNotFound() { // Arrange var loanId = 999; // Use a loan ID that does not exist in the Loans.json file var expectedLoan = new Loan { Id = loanId, BookItemId = 101, PatronId = 202, LoanDate = DateTime.Now, DueDate = DateTime.Now.AddDays(14) }; _mockLoanRepository.GetLoan(loanId).Returns(expectedLoan); // Act var actualLoan = await _jsonLoanRepository.GetLoan(loanId); // Assert Assert.Null(actualLoan); }Aceite a sugestão de preenchimento automático que atribui um valor
loanIdque não está no conjunto de dados.Se nenhuma das sugestões atribuir números
loanIdque não estejam no conjunto de dados, você pode usar o atalho de teclado Ctrl+Enter para listar sugestões adicionais.Observe que os testes de unidade exigem acesso aos arquivos de dados JSON.
O método
JsonLoanRepository.GetLoanusa um objetoJsonDatapara carregar e salvar dados de empréstimo.Os arquivos de dados JSON estão localizados na pasta
Library.Console\Json. Você precisa atualizar o arquivoUnitTests.csprojpara incluir esses arquivos no projeto de teste.Adicione o seguinte snippet XML ao arquivo
UnitTests.csproj:<ItemGroup> <None Include="..\..\src\Library.Console\Json\**\*"> <Link>Json\%(RecursiveDir)%(FileName)%(Extension)</Link> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> </ItemGroup>Isso garante que os arquivos de dados JSON sejam copiados para o diretório de saída quando os testes forem executados.
Verifique seu trabalho
Há várias maneiras de executar os testes de unidade para a classe JsonLoanRepository. Você pode usar o comando dotnet test, o terminal integrado ou o Editor de Lista de Testes do Visual Studio Code.
Use as seguintes etapas para concluir esta seção do exercício:
Verifique se você abriu o arquivo GetLoans.cs no editor.
Compile a solução e verifique se não há nenhum erro.
Clique com o botão direito do mouse em AccelerateDevGitHubCopilot e selecione Compilar.
Observe o "botão de reprodução verde" à esquerda dos métodos de teste.
Abra a exibição do Editor de Lista de Testes no Visual Studio Code.
Para abrir o modo de exibição do Editor de Lista de Testes, selecione o ícone em forma de béquer na barra de atividades do lado esquerdo. O Editor de Lista de Testes é rotulado como "Teste" na interface do usuário.
O Editor de Lista de Testes é no modo de exibição de árvore para mostrar todos os casos de teste no seu workspace. Você pode executar/depurar seus casos de teste e ver seus resultados de teste usando o Editor de Lista de Testes.
Expanda UnitTests e os nós subjacentes para localizar
GetLoanTest.Execute o caso de teste JsonLoanRepository.GetLoan: Retorna o empréstimo quando a ID do empréstimo é encontrada.
Observe os resultados de teste no modo de exibição no Editor de Lista de Testes e no Editor.
Você deve ver uma marca de seleção verde que indica que o teste foi aprovado.
Use o Editor para executar o caso de teste JsonLoanRepository.GetLoan: Retorna nulo quando a ID do empréstimo não é encontrada.
Observe os resultados de teste no modo de exibição no Editor de Lista de Testes e no Editor.
Para executar o teste no Editor, selecione o botão de reprodução verde à esquerda do método de teste.
Verifique se o teste JsonLoanRepository.GetLoan: Retorna nulo quando a ID do empréstimo não é encontrada é aprovado.
Você deverá ver uma marca de seleção verde à esquerda de ambos os testes.