Árvore de páginas

Versões comparadas

Chave

  • Esta linha foi adicionada.
  • Esta linha foi removida.
  • A formatação mudou.

...

  • Microsoft.NET.Test.Sdk
  • NSubstitute
  • Shouldly
  • Tnf.TestBase.AppTnf.App.EntityFrameworkCore.TestBase
  • Microsoft.EntityFrameworkCore.InMemory
  • xunit
  • xunit.runner.visualstudio

...

  • Microsoft.NET.Test.Sdk
  • Microsoft.AspNetCore.TestHost
  • NSubstitute
  • Shouldly
  • Tnf.App.AspNetCore.TestBase
  • Tnf.App.EntityFrameworkCore.TestBase
  • xunit
  • xunit.runner.visualstudio

...

Bloco de código
languagec#
firstline1
titleAppTestModule
linenumberstrue
[DependsOn(
	typeof(AppModule),
    typeof(TnfTestBaseModuleTnfAppTestBaseModule))]
public class EfCoreAppTestModule : TnfModule
{
	public override void PreInitialize()
    {
    	Configuration.Modules
        	.TnfEfCoreInMemory(IocManager.IocContainer)
            .RegisterDbContextInMemory<ArchitectureDbContext>();
	}
    
    public override void Initialize()
	{
    	IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
    }
}

...

Também temos como dependência o modulo "TnfTestBaseModuleTnfAppTestBaseModule" do TNF carregando toda a estrutura de testes integrados.

...

Bloco de código
languagec#
firstline1
titleAppTestModule.cs
linenumberstrue
[DependsOn(
	typeof(AppModule),
    typeof(TnfTestBaseModuleTnfAppTestBaseModule))]
public class NSubstituteAppTestModule : TnfModule
{
	public override void PreInitialize()
	{
		// Mock repositories
        Configuration.ReplaceService<IWhiteHouseRepository>(() =>
        {
        	var instance = Substitute.For<IWhiteHouseRepository>();
            
            var presidentToInsert = new PresidentDto("1", "New President", "55833479");
    
            instance.InsertPresidentsAsync(Arg.Any<List<PresidentDto>>)
				.Returns(Task.FromResult(presidentToInsert));
 
			IocManager.IocContainer.Register(
            	Component
                	.For<IWhiteHouseRepository>()
                    .Instance(instance)
                    .LifestyleTransient()
			);
		});
	}

    public override void Initialize()
	{
		IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
	}
}

...

Também temos como dependência o modulo "TnfTestBaseModuleTnfAppTestBaseModule" para carregar a estrutura de testes integrados.

...

Após a definição do módulo vamos criar a classe de Setup para cada teste integrado: para isso a classe abaixo nomeada de "NSubstituteAppTestBase" realiza a herança da classe "TnfEfCoreIntegratedTestBase<Module>TnfAppIntegratedTestBase<Module>" que recebe um TnfModule (implementado anteriormente):

Bloco de código
languagec#
firstline1
titleAppTestBase.cs
linenumberstrue
public class NSubstituteAppTestBase : TnfIntegratedTestBase<NSubstituteAppTestModule>TnfAppIntegratedTestBase<NSubstituteAppTestModule>
{
}

A classe TnfIntegratedTestBase está TnfAppIntegratedTestBase está contida no pacote Tnf.App.TestBase.

Definido nosso setup podemos implementar nossa classe e realizar os testes usando nosso repositório criado com NSubstitute.

Bloco de código
languagec#
firstline1
titleWhiteHouseAppService
linenumberstrue
public class WriteHouseAppServiceTests : NSubstituteAppTestBase
{
	private readonly IWhiteHouseAppService _whiteHouseAppService;

    public WriteHouseAppServiceTests()
    {
    	_whiteHouseAppService = LocalIocManager.Resolve<IWhiteHouseAppService>();
	}
 
	[Fact]
    public async Task Should_Insert_President_With_Success()
    {
    	// Act
        var response = await _whiteHouseAppService.InsertPresidentAsync(new PresidentDto("1", "New President", "12345678"));
		
		// Assert
        Assert.TrueFalse(responseLocalNotification.SuccessHasNotification());
	}
}

Podemos perceber que toda a estrutura de Injeção de dependência ainda é mantida inclusive nos testes.

...

Bloco de código
languagec#
firstline1
titleAppTestModule.cs
linenumberstrue
[DependsOn(
	typeof(AppModule),
    typeof(TnfAspNetCoreTestBaseModuleTnfAppAspNetCoreTestBaseModule))]
public class AppTestModule : TnfModule
{
	public override void PreInitialize()
    {
    	Configuration.Auditing.IsEnabledForAnonymousUsers = true;

        // Mock repositories
        Configuration.ReplaceService<IWhiteHouseRepository, WhiteHouseRepositoryMock>();

		Configuration.Modules
        	.TnfEfCoreInMemory(IocManager.IocContainer, IocManager.Resolve<IServiceProvider>())
            .RegisterDbContextInMemory<ArchitectureDbContext>();
        }

        public override void Initialize()
        {
            IocManager.RegisterAssemblyByConvention(typeof(AppTestModule).GetAssembly());
        }
    }
}

...

Nosso modulo agora contem dependências diferente pois vamos testar uma camada de AspNetCore e por isso devemos deixar explicito em nosso atributo "DependsOn" o uso do modulo TnfAspNetCoreTestBaseModuleTnfAppAspNetCoreTestBaseModule.

Como estamos criando um teste para uma aplicação ASP .NET Core que expoe expõe nossas APIs, temos que criar uma classe de startup que fará a configuração de nosso pipeline:

Bloco de código
languagec#
firstline1
titleStartupTest.cs
linenumberstrue
public class StartupTest
{
	public IServiceProvider ConfigureServices(IServiceCollection services)
    {
    	services.AddMvc()
         	.AddApplicationPart(typeof(TnfAspNetCoreModule).GetAssembly())
   .AddMvcCore()            .AddApplicationPart(typeof(Tnf.Architecture.Web.Startup.WebModule).GetAssembly())
            .AddControllersAsServices();

		services.AddEntityFrameworkInMemoryDatabase();

        // Configure Tnf and Dependency Injection
        return services.AddTnf<AppTestModule>AddTnfApp<AppTestModule>(options =>
        {
        	// Test setup
            options.SetupTest();
		});
	}

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
    	app.UseTnf(); //Initializes Tnf framework.
        app.UseMvc(routes =>
        {
        	routes.MapRoute(
            	name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
	}
}

...

  • AddEntityFrameworkInMemoryDatabase: Neste ponto configuramos o uso do Entity Framework em memoria para o pipeline do AspNetCore;
  • AddTnfAddTnfApp: adicionamos o suporte ao TNF, deixando explicito que estamos criando uma aplicação AspNetCore para testes passando nossa configuração de modulo (AppTestModule definido anteriormente);

...

Bloco de código
languagec#
firstline1
titleWhiteHouseControllerTests.cs
linenumberstrue
public class WhiteHouseControllerTests : AppTestBase
{
	[Fact]
    public void Should_Resolve_Controller()
    {
    	ServiceProvider.GetService<WhiteHouseController>().ShouldNotBeNull();
	}
 
	[Fact]
	public async Task GetAll_Presidents_With_Success()
	{
		        // Act
		        var response = await GetResponseAsObjectAsync<AjaxResponse<PagingDtoResponse<PresidentDto>>>GetResponseAsObjectAsync<ListDto<PresidentDto>>(
						     "/api/white-house?offset=0&pageSize=10",
						   HttpStatusCode.OK
					   );
		// Assert
		Assert.True(response.Success);
		Assert.Equal(response.Result.Data.Count, 6);
		response.Result.Notifications.ShouldBeEmpty();
	}
 
	[Fact]
	public async Task GetAll_Presidents_With_Invalid_Parameters()
	{
		// Act
		var response = await GetResponseAsObjectAsync<AjaxResponse<string>>(
			"/api/white-house?offset=0&pageSize=0",
			HttpStatusCode.BadRequest
			);
		response.Success.ShouldBeTrue();
		response.Result.ShouldBe($"Invalid parameter: pageSize"                   $"{RouteConsts.WhiteHouse}?pageSize=5",
                           HttpStatusCode.OK
                       );

        // Assert
        Assert.Equal(response.Items.Count, 5);
	}
 
	[Fact]
	public async Task GetAll_Presidents_With_Invalid_Parameters_Return_Bad_Request()
	{
        // Act
        var response = await GetResponseAsObjectAsync<ErrorResponse>(
                          $"{RouteConsts.WhiteHouse}",
                          HttpStatusCode.BadRequest
                       );

        // Assert
        response.Message.ShouldBe("GetAllPresident");
        response.DetailedMessage.ShouldBe("GetAllPresident");
        Assert.True(response.Details.Any(n => n.Message == Error.InvalidParameter.ToString()));
	}
}

Em nossa classe de teste temos acesso a alguns métodos pela herança da classe TnfAspNetCoreIntegratedTestBase contida dentro do pacote Tnf.AspNetCore.TestBase para criação de testes em serviços.

...