Organização e teste de projetos com o .NET Core CLIOrganizing and testing projects with the .NET Core CLI

Este tutorial segue a Introdução ao .NET Core no Windows/Linux/macOS, usando a linha de comando, e leva você além da criação de um simples aplicativo de console para desenvolver aplicativos avançados e bem organizados.This tutorial follows Get started with .NET Core on Windows/Linux/macOS using the command line, taking you beyond the creation of a simple console app to develop advanced and well-organized applications. Depois de mostrar como usar pastas para organizar seu código, este tutorial mostra como estender um aplicativo de console com a estrutura de teste xUnit.After showing you how to use folders to organize your code, this tutorial shows you how to extend a console application with the xUnit testing framework.

Usar pastas para organizar o códigoUsing folders to organize code

Se você quiser introduzir novos tipos em um aplicativo de console, poderá fazer isso adicionando arquivos que contêm os tipos para o aplicativo.If you want to introduce new types into a console app, you can do so by adding files containing the types to the app. Por exemplo, se você adicionar arquivos contendo os tipos AccountInformation e MonthlyReportRecords ao seu projeto, a estrutura do arquivo de projeto será simples e fácil de navegar:For example if you add files containing AccountInformation and MonthlyReportRecords types to your project, the project file structure is flat and easy to navigate:

/MyProject
|__AccountInformation.cs
|__MonthlyReportRecords.cs
|__MyProject.csproj
|__Program.cs

No entanto, isso funciona bem apenas quando o projeto é relativamente pequeno.However, this only works well when the size of your project is relatively small. Você pode imaginar o que acontecerá se adicionar 20 tipos ao projeto?Can you imagine what will happen if you add 20 types to the project? O projeto definitivamente não será fácil navegar e manter com tantos arquivos dividindo o diretório raiz do projeto.The project definitely wouldn't be easy to navigate and maintain with that many files littering the project's root directory.

Para organizar o projeto, crie uma nova pasta e nomeie-a como Modelos para armazenar os arquivos do tipo.To organize the project, create a new folder and name it Models to hold the type files. Coloque os arquivos de tipo na pasta Modelos:Place the type files into the Models folder:

/MyProject
|__/Models
   |__AccountInformation.cs
   |__MonthlyReportRecords.cs
|__MyProject.csproj
|__Program.cs

Projetos que agrupam arquivos em pastas de forma lógica são fáceis de navegar e manter.Projects that logically group files into folders are easy to navigate and maintain. Na próxima seção, você criará um exemplo mais complexo com pastas e testes de unidade.In the next section, you create a more complex sample with folders and unit testing.

Organizando e testando usando o Exemplo Pets de NewTypesOrganizing and testing using the NewTypes Pets Sample

Compilando o exemploBuilding the sample

Para as etapas a seguir, você pode acompanhar usando o NewTypes Pets Sample (Exemplo Pets de NewTypes) ou criar seus próprios arquivos e pastas.For the following steps, you can either follow along using the NewTypes Pets Sample or create your own files and folders. Os tipos são organizados logicamente em uma estrutura de pastas que permite a adição de mais tipos posteriormente e os testes também são posicionados logicamente nas pastas, permitindo a adição de mais testes posteriormente.The types are logically organized into a folder structure that permits the addition of more types later, and tests are also logically placed in folders permitting the addition of more tests later.

Esse exemplo contém dois tipos, Dog e Cat, e faz com que eles implementem uma interface comum, IPet.The sample contains two types, Dog and Cat, and has them implement a common interface, IPet. Para o projeto NewTypes, sua meta é organizar os tipos relacionados a animais de estimação em uma pasta Pets.For the NewTypes project, your goal is to organize the pet-related types into a Pets folder. Se outro conjunto de tipos for adicionado posteriormente, WildAnimals por exemplo, ele será colocado na pasta NewTypes junto com a pasta Pets.If another set of types is added later, WildAnimals for example, they're placed in the NewTypes folder alongside the Pets folder. A pasta WildAnimals pode conter tipos de animais que não são animais de estimação, como os tipos Squirrel e Rabbit.The WildAnimals folder may contain types for animals that aren't pets, such as Squirrel and Rabbit types. Dessa forma, conforme os tipos são adicionados, o projeto continua bem organizado.In this way as types are added, the project remains well organized.

Crie a seguinte estrutura de pasta com o conteúdo do arquivo indicado:Create the following folder structure with file content indicated:

/NewTypes
|__/src
   |__/NewTypes
      |__/Pets
         |__Dog.cs
         |__Cat.cs
         |__IPet.cs
      |__Program.cs
      |__NewTypes.csproj

IPet.cs:IPet.cs:

using System;

namespace Pets
{
    public interface IPet
    {
        string TalkToOwner();
    }
}

Dog.cs:Dog.cs:

using System;

namespace Pets
{
    public class Dog : IPet
    {
        public string TalkToOwner() => "Woof!";
    }
}

Cat.cs:Cat.cs:

using System;

namespace Pets
{
    public class Cat : IPet
    {
        public string TalkToOwner() => "Meow!";
    }
}

Program.cs:Program.cs:

using System;
using Pets;
using System.Collections.Generic;

namespace ConsoleApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            List<IPet> pets = new List<IPet>
            {
                new Dog(),
                new Cat()  
            };
            
            foreach (var pet in pets)
            {
                Console.WriteLine(pet.TalkToOwner());
            }
        }
    }
}

NewTypes.csproj:NewTypes.csproj:

<Project Sdk="Microsoft.NET.Sdk">
  
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.2</TargetFramework>
  </PropertyGroup>

</Project>

Execute o comando a seguir:Execute the following command:

dotnet run

Obtenha a seguinte saída:Obtain the following output:

Woof!
Meow!

Exercício opcional: você pode adicionar um novo tipo de animal de estimação, como um Bird, estendendo esse projeto.Optional exercise: You can add a new pet type, such as a Bird, by extending this project. Faça com que o método TalkToOwner de pássaro dê um Tweet! para o proprietário.Make the bird's TalkToOwner method give a Tweet! to the owner. Execute o aplicativo novamente.Run the app again. A saída incluirá Tweet!The output will include Tweet!

Testando o exemploTesting the sample

O projeto NewTypes está em funcionamento e você o organizou mantendo os tipos relacionados a animais de estimação em uma pasta.The NewTypes project is in place, and you've organized it by keeping the pets-related types in a folder. Em seguida, crie seu projeto de teste e comece a escrever testes com a estrutura de teste xUnit.Next, create your test project and start writing tests with the xUnit test framework. O teste de unidade permite que você verifique automaticamente o comportamento dos seus tipos de animal de estimação para confirmar se eles estão funcionando corretamente.Unit testing allows you to automatically check the behavior of your pet types to confirm that they're operating properly.

Navegue de volta para a pasta src e crie uma pasta test com uma pasta NewTypesTests dentro dela.Navigate back to the src folder and create a test folder with a NewTypesTests folder within it. Em um prompt de comando da pasta NewTypesTests, execute dotnet new xunit.At a command prompt from the NewTypesTests folder, execute dotnet new xunit. Isso gera dois arquivos: NewTypesTests.csproj e UnitTest1.cs.This produces two files: NewTypesTests.csproj and UnitTest1.cs.

No momento, o projeto de teste não pode testar os tipos no NewTypes e requer uma referência de projeto para o projeto NewTypes.The test project cannot currently test the types in NewTypes and requires a project reference to the NewTypes project. Para adicionar uma referência dotnet add reference de projeto, use o comando:To add a project reference, use the dotnet add reference command:

dotnet add reference ../../src/NewTypes/NewTypes.csproj

Se preferir, adicione manualmente a referência de projeto adicionando um nó <ItemGroup> ao arquivo NewTypesTests.csproj:Or, you also have the option of manually adding the project reference by adding an <ItemGroup> node to the NewTypesTests.csproj file:

<ItemGroup>
  <ProjectReference Include="../../src/NewTypes/NewTypes.csproj" />
</ItemGroup>

NewTypesTests.csproj:NewTypesTests.csproj:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
    <PackageReference Include="xunit" Version="2.4.1" />
    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="../../src/NewTypes/NewTypes.csproj"/>
  </ItemGroup>

</Project>

O arquivo NewTypesTests.csproj com o seguinte:The NewTypesTests.csproj file contains the following:

  • Referência de pacote para Microsoft.NET.Test.Sdk, a infraestrutura de teste do .NETPackage reference to Microsoft.NET.Test.Sdk, the .NET testing infrastructure
  • Referência de pacote para xunit, a estrutura de teste do xUnitPackage reference to xunit, the xUnit testing framework
  • Referência de pacote para xunit.runner.visualstudio, o executor de testePackage reference to xunit.runner.visualstudio, the test runner
  • Referência de projeto para NewTypes, o código a ser testadoProject reference to NewTypes, the code to test

Altere o nome de UnitTest1.cs para PetTests.cs e substitua o código no arquivo pelo seguinte:Change the name of UnitTest1.cs to PetTests.cs and replace the code in the file with the following:

using System;
using Xunit;
using Pets;

public class PetTests
{
    [Fact]
    public void DogTalkToOwnerReturnsWoof()
    {
        string expected = "Woof!";
        string actual = new Dog().TalkToOwner();

        Assert.NotEqual(expected, actual);
    }

    [Fact]
    public void CatTalkToOwnerReturnsMeow()
    {
        string expected = "Meow!";
        string actual = new Cat().TalkToOwner();

        Assert.NotEqual(expected, actual);
    }
}

Exercício opcional: se você adicionou um tipo Bird anteriormente que produz um Tweet! para o proprietário, adicione um método de teste ao arquivo PetTests.cs, BirdTalkToOwnerReturnsTweet, para verificar se o método TalkToOwner funciona corretamente para o tipo Bird.Optional exercise: If you added a Bird type earlier that yields a Tweet! to the owner, add a test method to the PetTests.cs file, BirdTalkToOwnerReturnsTweet, to check that the TalkToOwner method works correctly for the Bird type.

Observação

Embora você espere que os valores expected e actual sejam iguais, uma declaração inicial com a verificação Assert.NotEqual especifica que esses valores não são iguais.Although you expect that the expected and actual values are equal, an initial assertion with the Assert.NotEqual check specifies that these values are not equal. Sempre crie inicialmente os testes para falhar para verificar a lógica do teste.Always initially create a test to fail in order to check the logic of the test. Depois de confirmar que o teste falhou, ajuste a declaração para permitir que o teste seja aprovado.After you confirm that the test fails, adjust the assertion to allow the test to pass.

O código a seguir mostra a estrutura do projeto completo:The following shows the complete project structure:

/NewTypes
|__/src
   |__/NewTypes
      |__/Pets
         |__Dog.cs
         |__Cat.cs
         |__IPet.cs
      |__Program.cs
      |__NewTypes.csproj
|__/test
   |__NewTypesTests
      |__PetTests.cs
      |__NewTypesTests.csproj

Inicie no diretório test/NewTypesTests.Start in the test/NewTypesTests directory. Restaure o projeto dotnet restore de teste com o comando.Restore the test project with the dotnet restore command. Execute os testes dotnet test com o comando.Run the tests with the dotnet test command. Esse comando inicia o executor de teste especificado no arquivo de projeto.This command starts the test runner specified in the project file.

Observação

Começando com o .NET Core 2.0 SDK, dotnet restore você não precisa ser executado porque é executado implicitamente dotnet new dotnet build por dotnet runtodos os comandos que requerem uma restauração para ocorrer, tais como , e .Starting with .NET Core 2.0 SDK, you don't have to run dotnet restore because it's run implicitly by all commands that require a restore to occur, such as dotnet new, dotnet build and dotnet run. Ainda é um comando válido em determinados cenários em que realizar uma restauração explícita faz sentido, como builds de integração contínua no Azure DevOps Services ou em sistemas de build que precisam controlar explicitamente o horário em que a restauração ocorrerá.It's still a valid command in certain scenarios where doing an explicit restore makes sense, such as continuous integration builds in Azure DevOps Services or in build systems that need to explicitly control the time at which the restore occurs.

Conforme o esperado, o teste falha e o console exibe a seguinte saída:As expected, testing fails, and the console displays the following output:

Test run for c:\Users\ronpet\repos\samples\core\console-apps\NewTypesMsBuild\test\NewTypesTests\bin\Debug\netcoreapp2.1\NewTypesTests.dll(.NETCoreApp,Version=v2.1)
Microsoft (R) Test Execution Command Line Tool Version 15.8.0
Copyright (c) Microsoft Corporation.  All rights reserved.

Starting test execution, please wait...
[xUnit.net 00:00:00.77]     PetTests.DogTalkToOwnerReturnsWoof [FAIL]
[xUnit.net 00:00:00.78]     PetTests.CatTalkToOwnerReturnsMeow [FAIL]
Failed   PetTests.DogTalkToOwnerReturnsWoof
Error Message:
 Assert.NotEqual() Failure
Expected: Not "Woof!"
Actual:   "Woof!"
Stack Trace:
   at PetTests.DogTalkToOwnerReturnsWoof() in c:\Users\ronpet\repos\samples\core\console-apps\NewTypesMsBuild\test\NewTypesTests\PetTests.cs:line 13
Failed   PetTests.CatTalkToOwnerReturnsMeow
Error Message:
 Assert.NotEqual() Failure
Expected: Not "Meow!"
Actual:   "Meow!"
Stack Trace:
   at PetTests.CatTalkToOwnerReturnsMeow() in c:\Users\ronpet\repos\samples\core\console-apps\NewTypesMsBuild\test\NewTypesTests\PetTests.cs:line 22

Total tests: 2. Passed: 0. Failed: 2. Skipped: 0.
Test Run Failed.
Test execution time: 1.7000 Seconds

Altere as asserções de seus testes de Assert.NotEqual para Assert.Equal:Change the assertions of your tests from Assert.NotEqual to Assert.Equal:

using System;
using Xunit;
using Pets;

public class PetTests
{
    [Fact]
    public void DogTalkToOwnerReturnsWoof()
    {
        string expected = "Woof!";
        string actual = new Dog().TalkToOwner();

        Assert.Equal(expected, actual);
    }

    [Fact]
    public void CatTalkToOwnerReturnsMeow()
    {
        string expected = "Meow!";
        string actual = new Cat().TalkToOwner();

        Assert.Equal(expected, actual);
    }
}

Execute novamente os testes com o comando dotnet test e obtenha a seguinte saída:Re-run the tests with the dotnet test command and obtain the following output:

Test run for c:\Users\ronpet\repos\samples\core\console-apps\NewTypesMsBuild\test\NewTypesTests\bin\Debug\netcoreapp2.1\NewTypesTests.dll(.NETCoreApp,Version=v2.1)
Microsoft (R) Test Execution Command Line Tool Version 15.8.0
Copyright (c) Microsoft Corporation.  All rights reserved.

Starting test execution, please wait...

Total tests: 2. Passed: 2. Failed: 0. Skipped: 0.
Test Run Successful.
Test execution time: 1.6029 Seconds

O teste é aprovado.Testing passes. Os métodos dos tipos de animais de estimação retornam os valores corretos ao conversar com o proprietário.The pet types' methods return the correct values when talking to the owner.

Você aprendeu técnicas para organizar e testar projetos usando xUnit.You've learned techniques for organizing and testing projects using xUnit. Prossiga com essas técnicas aplicando-as em seus próprios projetos.Go forward with these techniques applying them in your own projects. Boa codificação!Happy coding!