<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alessandra Souza</title>
    <description>The latest articles on DEV Community by Alessandra Souza (@alsouza93).</description>
    <link>https://dev.to/alsouza93</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F484532%2F44ebc73b-d37e-414c-86c1-baeae88a6859.jpeg</url>
      <title>DEV Community: Alessandra Souza</title>
      <link>https://dev.to/alsouza93</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alsouza93"/>
    <language>en</language>
    <item>
      <title>Teste de Unidade</title>
      <dc:creator>Alessandra Souza</dc:creator>
      <pubDate>Sun, 25 Apr 2021 19:30:32 +0000</pubDate>
      <link>https://dev.to/alsouza93/teste-de-unidade-2g95</link>
      <guid>https://dev.to/alsouza93/teste-de-unidade-2g95</guid>
      <description>&lt;p&gt;Teste de Unidade: É o teste da menor unidade testável de um programa.&lt;/p&gt;

&lt;p&gt;Em português é comum falar teste unitário, porém o mais correto é o termo teste de unidade. Teste unitário da a sensação que é apenas um teste, no entanto podemos criar vários cenários para testar o seu método.&lt;/p&gt;

&lt;p&gt;Um teste de unidade precisa ser:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Rápido: Não é incomum para projetos maduros ter milhares de testes de unidade. Os testes de unidade devem levar muito pouco tempo para serem executados. Milissegundos.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Isolado: Testes de unidade são autônomos e não têm dependências de nenhum fator externo, como um sistema de arquivos ou o banco de dados. Mesmo um teste de integração, as dependências externas são resolvidas com o uso do InMemoryDataBase ou com mocks. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Repetível: A execução de um teste de unidade deve ser consistente com seus resultados, ou seja, ele sempre retornará o mesmo resultado se você não alterar nada entre execuções. Se o teste hora passa, e hora não, talvez ele esteja compartilhando estado de algum objeto.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Verificação automática: O teste deve ser capaz de detectar automaticamente se ele foi aprovado ou reprovado sem nenhuma interação humana.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Em tempo hábil: Um teste de unidade não deve levar muito tempo para ser escrito comparado com o código que está sendo testado.  Se você demorar muito tempo para escrever o teste, considere um design mais estável ou um refactoring.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Como nomear os Testes?
&lt;/h2&gt;

&lt;p&gt;Modelo 01:&lt;br&gt;
ObjetoEmTeste_MetodoComportamentoEmTeste_ComportamentoEsperado &lt;br&gt;
Ex: Pedido_AdicionarItem_DeveExibirErroSeItemJaAdicionado&lt;/p&gt;

&lt;p&gt;Modelo 02:&lt;br&gt;
MetodoEmTeste_EstadoEmTeste_ComportamentoEsperado&lt;br&gt;
Ex: AdicionarItem_ItemJaExistente_DeveExibirErroSeItemJaAdicionado&lt;/p&gt;
&lt;h2&gt;
  
  
  Padrão AAA
&lt;/h2&gt;

&lt;p&gt;O padrão AAA auxilia na organização do teste e deixa ele mais legível.&lt;/p&gt;

&lt;p&gt;Arrange: onde é preparado os objetos para serem testados.&lt;br&gt;
Act: onde fica a ação a ser executada.&lt;br&gt;
Assert: onde ficam as comparações.&lt;/p&gt;

&lt;p&gt;Evite usar os métodos de Setup e Teardown para criar objetos utilizados no teste, assim você terá:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Menos confusão ao ler os testes, uma vez que todo o código está visível dentro de cada teste;&lt;/li&gt;
&lt;li&gt;Menos chance de configurar demais ou de menos para o teste específico;&lt;/li&gt;
&lt;li&gt;Menos chance de compartilhar o estado entre os testes, que cria dependências indesejadas entre eles.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Evite o uso de mais de um assert no teste, pois assim você garante que não está declarando vários cenários no mesmo teste.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Uma exceção a regra é um assert sobre propriedades de um objeto.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Frameworks para teste
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;MsTest: Desenvolvido pela Microsoft.&lt;/li&gt;
&lt;li&gt;nUnit: Desenvolvido e mantido pelo .Net Foundations. &lt;/li&gt;
&lt;li&gt;xUnit: Desenvolvido pelos mesmos criadores do nUnit e é o mais recente framework para testes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Segue comparação entre os frameworks no &lt;a href="https://xunit.net/docs/comparisons"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Apesar da Microsoft ter desenvolvido o MsTest, atualmente ela recomenda o uso do xUnit.&lt;/p&gt;
&lt;h2&gt;
  
  
  Exemplos com xUnit
&lt;/h2&gt;

&lt;p&gt;Vamos ver agora alguns exemplos de teste de unidade, usando o framework xUnit e os padrões de nomenclatura e organização dos testes.&lt;/p&gt;

&lt;p&gt;O teste abaixo verifica se um cpf é válido.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Fact]
public void SocialNumber_IsValid_ReturnTrueForValidValue()
{
    //Arrange          
    //Act
    var result = SocialNumber.IsValid("52812349000");

    //Assert
    Assert.True(result);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No xUnit para testar mais de um valor pode-se utilizar o Theory, assim seu teste fica mais limpo.&lt;/p&gt;

&lt;p&gt;O teste a seguir verifica se cada cpf informado no InlineData é válido.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Theory]
[InlineData("557.287.970-32")]
[InlineData("016.118.090-61")]
[InlineData("143.504.220-48")]
[InlineData("660.352.030-35")]
[InlineData("93355758019")]
[InlineData("77228802071")]
[InlineData("24780314003")]    
public void SocialNumber_IsValid_ReturnTrueForValidValues(string value)
{
    //Arrange          
    //Act
    var result = SocialNumber.IsValid(value);

    //Assert
    Assert.True(result);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para finalizar, um exemplo testando exceções.&lt;/p&gt;

&lt;p&gt;O teste a seguir, verifica se uma determinada exceção é lançada ao informar um valor nulo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Fact]
public void SocialNumber_Constructor_ThrowsExceptionForNullValues()
{
    //Arrange          
    //Act   
    //Assert
    var ex = Assert.Throws&amp;lt;ArgumentNullException&amp;gt;(() =&amp;gt; SocialNumber.FromString(null));
    Assert.Equal("Value cannot be null. (Parameter 'value')", ex.Message);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Caso queira ver o código completo, segue o &lt;a href="https://github.com/alsouza93/LoanBookApi/blob/main/LoanBook.Api.UnitTests/SocialNumberTest.cs"&gt;link&lt;/a&gt; do GitHub.&lt;/p&gt;

&lt;h2&gt;
  
  
  Referências
&lt;/h2&gt;

&lt;p&gt;Recomendo a leitura deste artigo da Microsoft. Nada melhor do que beber a água direto da fonte.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices"&gt;https://docs.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se quiser se aprofundar mais no assunto, também recomendo o curso "Dominando os Testes de Software" do Eduardo Pires na plataforma &lt;a href="https://desenvolvedor.io"&gt;https://desenvolvedor.io&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>csharp</category>
      <category>xunit</category>
      <category>api</category>
    </item>
    <item>
      <title>Mockando Injeção de Dependência em Testes Integrados no ASP.NET 3.1</title>
      <dc:creator>Alessandra Souza</dc:creator>
      <pubDate>Thu, 08 Oct 2020 17:10:30 +0000</pubDate>
      <link>https://dev.to/alsouza93/mockando-injecao-de-dependencia-em-testes-integrados-no-asp-net-3-1-2k9l</link>
      <guid>https://dev.to/alsouza93/mockando-injecao-de-dependencia-em-testes-integrados-no-asp-net-3-1-2k9l</guid>
      <description>&lt;h4&gt;
  
  
  O que é um Teste de Integração?
&lt;/h4&gt;

&lt;p&gt;O teste de integração é o teste entre diferentes módulos em um sistema, testando a integração entre as unidades. Muito útil para testar &lt;em&gt;middlewares&lt;/em&gt;, mas além disso é possível testar uma requisição completa, evitando falhas como as citadas abaixo:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Erros de interpretação:&lt;/strong&gt; ocorre quando uma funcionalidade está implementada diferente da especificação.&lt;br&gt;
&lt;strong&gt;Chamadas incorretas:&lt;/strong&gt; quando existe a chamada de unidades em locais errados.&lt;br&gt;
&lt;strong&gt;Erros de interface:&lt;/strong&gt; quando o padrão de integração entre as unidades foi implementado erroneamente, seja a ordem, tipo ou formato de parâmetros errados.&lt;/p&gt;

&lt;p&gt;Para este tutorial, foram feitas algumas modificações na API que o próprio modelo ASP.NET Core Web Application cria ao inicializar um novo projeto.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; [ApiController]
public class WeatherForecastController : ControllerBase
{
    private readonly IWeatherService _weatherService;
    public WeatherForecastController(IWeatherService weatherService)
    {
        _weatherService = weatherService;
    }

    [HttpGet("/report")]
    public ContentResult GetWeatherForecastReport()
    {
        return new ContentResult()
        {
            Content = _weatherService.WriteWeatherForecastReport(),
            StatusCode = 200
        };
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Criei uma camada de serviço e repositório para obter a previsão do tempo ao invés de deixar este código na controller. &lt;/p&gt;

&lt;p&gt;Agora iremos partir para o teste de integração!&lt;/p&gt;

&lt;h4&gt;
  
  
  Criação de um Teste de Integração
&lt;/h4&gt;

&lt;p&gt;Para criar um teste de integração é necessário criar um host e para isso utilizaremos o HostBuilder. Para saber mais sobre host e as mudanças do Asp.Net Core 3.1 para as versões anteriores, eu sugiro a leitura deste artigo. &lt;a href="https://stackoverflow.com/questions/52085806/what-is-the-difference-between-iwebhost-webhostbuilder-buildwebhost"&gt;Link&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var hostBuilder = new HostBuilder()
            .ConfigureWebHost(webHost =&amp;gt;
            {                      
                webHost.UseTestServer();
                webHost.UseEnvironment("Test");
                webHost.UseStartup&amp;lt;Startup&amp;gt;();
            });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;em&gt;UseTestServer&lt;/em&gt; indica que iremos utilizar o &lt;em&gt;TestServer&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Nota: O &lt;em&gt;UseTestServer&lt;/em&gt; está dentro do pacote Microsoft.AspNetCore.Mvc.Testing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Em UseEnvironment indicamos qual ambiente iremos utilizar para realizar o teste.&lt;/p&gt;

&lt;p&gt;Por último informamos qual classe Startup iremos utilizar.&lt;/p&gt;

&lt;p&gt;Após construir o host, precisamos inicializá-lo, e para isso utilizamos o código abaixo:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;var host = hostBuilder.StartAsync();&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Agora é necessário criar uma instância para este servidor em memória que acabamos de criar.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;var client = host.GetTestClient();&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Por fim, fazemos a chamada do endpoint.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;var response =  client.GetAsync("/report");&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Vamos ver agora como ficou o teste completo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Fact]
public void TestReport()
{
    //Arrange
    var hostBuilder = new HostBuilder()
            .ConfigureWebHost(webHost =&amp;gt;
            {                      
                webHost.UseTestServer();
                webHost.UseEnvironment("Test");
                webHost.UseStartup&amp;lt;Startup&amp;gt;();
            });

    var host = hostBuilder.Start();
    var client = host.GetTestClient();

    // Act
    var response =  client.GetAsync("/report");
    var responseString = response.Result.Content.ReadAsStringAsync();

    // Assert
    Assert.NotNull(responseString);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Teste de Integração Trocando a Injeção de Dependência
&lt;/h4&gt;

&lt;p&gt;Agora que você já sabe a estrutura básica de um teste de integração no Asp.Net Core 3.1, vamos aprender como trocar a injeção de dependência.&lt;/p&gt;

&lt;p&gt;No cenário anterior, temos a controller com uma injeção de dependência para o serviço e o serviço dependia de uma interface do tipo IWeatherRepository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class WeatherRepository : IWeatherRepository
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    public WeatherForecast GetWeatherForecast()
    {
        var rng = new Random();
        return  new WeatherForecast
        {
            Date = DateTime.Now,
            TemperatureC = rng.Next(-20, 55),
            Summary = Summaries[rng.Next(Summaries.Length)]
        };

    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O repositório simplesmente devolvia uma previsão do tempo randômica, mas e se quisermos trocar por um repositório fake que esteja no projeto de teste para sempre nos devolver uma mesma previsão do tempo? &lt;/p&gt;

&lt;p&gt;Para isso será necessário adicionar uma configuração a mais no construtor do host. &lt;/p&gt;

&lt;p&gt;Na construção do host, temos acesso ao método ConfigureTestServices. Caso ele seja adicionado depois do UseStartup, nós podemos acessar o IServiceCollection que foi gerado anteriormente para criar um provedor de serviços.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;webHost.ConfigureTestServices(services =&amp;gt;
     {
         services.SwapTransient&amp;lt;IWeatherRepository, FakeWeatherRepository&amp;gt;();
     });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com o método abaixo, podemos buscar qual foi a implementação configurada na Startup para a interface, e realizar a troca pela implementação que quisermos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static void SwapTransient&amp;lt;TService, TImplementation&amp;gt;(this IServiceCollection services)
where TImplementation : class, TService
{
    if (services.Any(x =&amp;gt; x.ServiceType == typeof(TService) &amp;amp;&amp;amp; x.Lifetime == ServiceLifetime.Transient))
    {
        var serviceDescriptors = services.Where(x =&amp;gt; x.ServiceType == typeof(TService) &amp;amp;&amp;amp;
        x.Lifetime == ServiceLifetime.Transient).ToList();
        foreach (var serviceDescriptor in serviceDescriptors)
        {
            services.Remove(serviceDescriptor);
        }
    }

    services.AddTransient(typeof(TService), typeof(TImplementation));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O método de teste ficou assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Fact]
public void TestReportWithFixForecast()
{
    //Arrange
    var hostBuilder = new HostBuilder()
         .ConfigureWebHost(webHost =&amp;gt;
         {
             webHost.UseTestServer();
             webHost.UseEnvironment("Test");
             webHost.UseStartup&amp;lt;Startup&amp;gt;();
             webHost.ConfigureTestServices(services =&amp;gt;
             {
                 services.SwapTransient&amp;lt;IWeatherRepository, FakeWeatherRepository&amp;gt;();
             });
         });

    var host = hostBuilder.Start();
    var client = host.GetTestClient();

    // Act
    var response = client.GetAsync("/report");
    var responseString = response.Result.Content.ReadAsStringAsync();

    // Assert
    Assert.Equal("Today's weather is Warm. With temperature 73", responseString.Result);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Caso queira consultar o código utilizado neste artigo, é só acessar o link do repositório no &lt;a href="https://github.com/alsouza93/IntegrationTestApi.git"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Referências
&lt;/h4&gt;

&lt;p&gt;Este artigo foi fortemente baseado em uma série de artigos do &lt;a href="https://adamstorr.azurewebsites.net/blog/integration-testing-with-aspnetcore-3-1"&gt;Adam Storr&lt;/a&gt;, indico a leitura caso tenha interesse em se aprofundar mais no assunto.&lt;/p&gt;

&lt;p&gt;Caso queira saber mais sobre testes de integração indico a leitura desta &lt;a href="https://teses.usp.br/teses/disponiveis/55/55134/tde-01082017-155344/publico/MariaAdelinaSilvaBrito_revisada.pdf"&gt;tese&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Por fim não deixe de ler a documentação do &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-3.1"&gt;ASP.NET Core&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>testing</category>
      <category>aspnetcor</category>
    </item>
  </channel>
</rss>
