Prodest.IntegrationTests.Containers 6.0.10

This package has a SemVer 2.0.0 package version: 6.0.10+20231207010202.
dotnet add package Prodest.IntegrationTests.Containers --version 6.0.10
NuGet\Install-Package Prodest.IntegrationTests.Containers -Version 6.0.10
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Prodest.IntegrationTests.Containers" Version="6.0.10" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Prodest.IntegrationTests.Containers --version 6.0.10
#r "nuget: Prodest.IntegrationTests.Containers, 6.0.10"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Prodest.IntegrationTests.Containers as a Cake Addin
#addin nuget:?package=Prodest.IntegrationTests.Containers&version=6.0.10

// Install Prodest.IntegrationTests.Containers as a Cake Tool
#tool nuget:?package=Prodest.IntegrationTests.Containers&version=6.0.10

Prodest.IntegrationTests.Containers

Sobre

Biblioteca para utilizar containers durante a execução de testes de integração, onde todo o ciclo de vida da api e containers é atrelado ao teste em execução, onde tudo é parado e descartado após a sua conclusão.

Como usar?

  1. Faça a sua classe de testes herdar a classe BaseTests:
public sealed class AcmeTests : BaseTests

E Implemente um construtor na classe derivada que recebe um ITestOutputHelper e passa para a classe base. Esse helper é Xunit e ajuda a captura de output de textos, visto que o Console.WriteLine não funciona nos testes. Exemplo:

/// <inheritdoc />
public AcmeTests(ITestOutputHelper output) : base(output)
{
}
  1. Na definição do seu método de teste (ex: Fact), instancie a classe SutFactory no campo _sut que está definido na classe BaseTests:
_sut = new SutFactory(
    8001,
    _output,
    builder =>
    {
        // defina as suas injeções aqui
    },
    application => {
        // defina os seus endpoints e middlewares aqui
    }
);

O primeiro parâmetro da instância é a porta da "api" que será levantada durante a execução do teste, defina valores diferentes para cada classe de teste, pode ser interessante criar uma constante na classe.

  1. Agora é necessário iniciar a instância, aqui você controla se vai usar containers ou não:
await _sut.UseSqlServerContainer();

Inicialização sem nenhum container definido.

await _sut.UseRedisContainer()
    .UseSqlServerContainer()
    .InitializeAsync();

Inicialização feita com os containers de redis e sqlserver.

Após a incialização, as dependências injetadas podem ser obtidas através do método _sut.GetDependency<T>, exemplo:

var configuration = _sut.GetDependency<IConfiguration>();

Buscando a instância do IConfiguration que foi injetada.

Exemplo de um método de teste completo:

[Fact]
public async Task EnviarAvaliacao_DbInterceptorThrowsException_ReturnsDomainErrorCode()
{
    // Arrange
    await ArrangeApi(builder =>
    {
        builder.Services
            .RemoveAll<BaseAvaliaEsContext>()
            .RemoveAll<DbContextOptions<BaseAvaliaEsContext>>();

        builder.Services
            .AddDbContext<BaseAvaliaEsContext, TestAvaliaEsContext>();
    });

    await Task.Delay(1);

    var dbContext = _sut!.GetDependency<BaseAvaliaEsContext>();
    var httpClient = _sut.GetDependency<IHttpClientFactory>()
        .CreateClient();

    var chaveAvaliacao = new ChaveAvaliacao
    {
        Data = DateTimeOffset.Now,
        IdExterno = Guid.NewGuid(),
        IdServico = Guid.Parse(Constants.GuidPrimeiraViaRg),
        IdSistema = Guid.Parse(Constants.GuidConectaEs),
        UrlRetorno = "https://foo.bar"
    };

    await dbContext.Database
        .EnsureCreatedAsync();

    await dbContext.ChaveAvaliacoes
        .AddAsync(chaveAvaliacao);
    await dbContext.SaveChangesAsync();

    var avaliacaoDto = new AvaliacaoEnvioDto
    {
        ChaveAvaliacao = chaveAvaliacao.IdExterno,
        IdCidadao = Guid.NewGuid(),
        Nota = 5,
        Opcoes = new List<Guid>()
    };

    // Act
    var response = await httpClient.PostAsJsonAsync(
        $"http://localhost:{ApiPort}/EnviarAvaliacao", avaliacaoDto
    );
    var result = await response.Content
        .ReadFromJsonAsync<Result<bool>>();

    // Assert
    result.Should()
        .NotBeNull();

    result!.IsOk()
        .Should()
        .BeFalse();

    result.ErrorCode
        .Should()
        .NotBeNullOrEmpty()
        .And
        .Be(DomainErrorCodes.ErroAoSalvarAvaliacao);
}

private async Task ArrangeApi(
    Action<WebApplicationBuilder>? configureBuilder = null,
    [CallerMemberName] string? memberName = ""
)
{
    _sut = new SutFactory(
        ApiPort,
        _output,
        builder =>
        {
            builder.Services
                .AddHttpClient();

            builder.Services
                .AddDbContext<BaseAvaliaEsContext, AvaliaEsContext>();

            builder.Services
                .InjectAcessoCidadaoIntegration(builder.Configuration)
                .InjectAllDependencies()
                .RemoveUnwantedServices(
                    typeof(IAvaliacaoApiService)
                );

            configureBuilder?.Invoke(builder);
        },
        application =>
        {
            application.Map(
                "EnviarAvaliacao",
                async (AvaliacaoEnvioDto dto, [FromServices] IAvaliacaoPublicoService service)
                    => await service.EnviarAvaliacao(dto)
            );
            application.Map(
                "ObterDadosChaveAvaliacao",
                async (ObterDadosAvaliacaoDto dto, [FromServices] IAvaliacaoPublicoService service)
                    => await service.ObterDadosChaveAvaliacao(dto)
            );
            application.Map(
                "ObterOpcoesAvaliacao",
                async ([FromServices] IAvaliacaoPublicoService service)
                    => await service.ObterOpcoesAvaliacao()
            );
        },
        memberName
    );

    await _sut.UseRedisContainer()
        .UseSqlServerContainer()
        .InitializeAsync();
}
Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
6.0.10 140 12/7/2023
6.0.9 62 11/27/2023
6.0.8 52 11/22/2023