Árvore de páginas

Versões comparadas

Chave

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

...

Cada teste executado no cenário acima será de forma reproduzido de forma isolada.

Testando a camada de aplicação com NSubstitute

Quando estamos trabalhando com repositórios sem o uso de um ORM por exemplo, precisamos fazer o mock da interface do repositório simulando um cenário afim de explorar todo o funcionamento do sistema.

Para isso o TNF possui uma extensão onde é possível realizar a substituição de uma injeção e usar o NSubstitute para criar objeto de mock para substitui-lo no injetor de dependência.

Para o seguinte cenário de testes que iremos construir considere a seguinte entidade e Dto:

Bloco de código
languagec#
firstline1
titlePresident.cs
linenumberstrue
[AutoMap(typeof(PresidentDto))]
public class President : Entity<string>
{
	public const int MaxNameLength = 256;
    public string Name { get; internal set; }
    public ZipCode ZipCode { get; internal set; }
    public enum Error
    {
    	Unexpected = 0,
        InvalidId = 1,
        PresidentNameMustHaveValue = 2,
        PresidentZipCodeMustHaveValue = 3,
	}
}
 
public class PresidentDto
{
	public PresidentDto()
    {
    }

    public PresidentDto(string id, string name, string zipCode)
    {
    	Id = id;
        Name = name;
        ZipCode = new ZipCode(zipCode);
	}

    public string Id { get; set; }
    public string Name { get; set; }
    public ZipCode ZipCode { get; set; }
}

Para realizar teste em cenários com o uso mocks o TNF prove alguns facilitadores.

Vamos começar com a criação do modulo que fará o carregamento da estrutura de testes:

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

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

O modulo "AppTestModule" foi criado no projeto de testes sendo responsável por carregar toda a estrutura de sua aplicação para o teste integrado.

Note que o atributo do modulo "DependsOn" tem como referencia outro modulo chamado "AppModule". Este modulo é um modulo da camada de aplicação de nossa aplicação concreta a ser testada. Esse modulo também contém dependências de outras camadas como domínio e infraestrutura onde estão definidos nossos repositórios de dados.

O código exemplificado acima, carrega o modulo da camada a ser testada, configurando no método "PreInitialize" os objetos de mock. No nosso exemplo estamos mocando

Através da função ReplaceService do TNF podemos usar o framework NSubstitute para então criar um objeto de mock para esse repositório e registrá-lo no container de injeção de dependência.

Para criação do Setup de cada teste o TNF disponibiliza uma classe abstrata chamada "TnfIntegratedTestBase<Module>" que recebe um TnfModule ("AppTestModule" vide exemplo anterior):

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

A classe TnfIntegratedTestBase está contida no pacote Tnf.TestBase em nosso feed: "https://www.myget.org/F/tnf/api/v3/index.json"

Definida a classe que fará o setup de cada teste criado, podemos começar a escrita de nossos testes sobre os serviços de aplicação:

Bloco de código
firstline1
titleIWhiteHouseService.cs
linenumberstrue
public interface IWhiteHouseAppService : IApplicationService
{
	Task<DtoResponseBase<PresidentDto>> InsertPresidentAsync(PresidentDto dto);
}
Bloco de código
languagec#
firstline1
titleWhiteHouseAppService.cs
linenumberstrue
public class WhiteHouseAppService : ApplicationService, IWhiteHouseAppService
{
	private readonly IWhiteHouseService _whiteHouserService;
 
	public WhiteHouseAppService(IWhiteHouseService whiteHouserService)
    {
    	_whiteHouserService = whiteHouserService;
	}
 
	public async Task<DtoResponseBase<PresidentDto>> InsertPresidentAsync(PresidentDto dto)
	{
    	var response = await _whiteHouserService.InsertPresidentAsync(dto);
        return response;
	}
}

Os serviços de aplicação consomem via injeção de dependência os serviços de domínio executando as validações presentes no builder da entidade:

Bloco de código
languagec#
firstline1
titleWhiteHouseService.cs
linenumberstrue
public interface IWhiteHouseService : IDomainService
{
	Task<DtoResponseBase<PresidentDto>> InsertPresidentAsync(PresidentDto president);
}
Bloco de código
languagec#
firstline1
titleWhiteHouseService
linenumberstrue
public class WhiteHouseService : DomainService<IWhiteHouseRepository>, IWhiteHouseService
{
    public WhiteHouseService(IWhiteHouseRepository repository)
            : base(repository)
    {
	}
	public async Task<DtoResponseBase<PresidentDto>> InsertPresidentAsync(PresidentDto president)
	{
		var response = new DtoResponseBase<PresidentDto>();
		var builder = new PresidentBuilder()
        	.WithId(item.Id)
            .WithName(item.Name)
            .WithZipCode(item.ZipCode);

		var build = builder.Build();
		if (!build.Success)
        	response.AddNotifications(build.Notifications);


		if (response.Success)
        {
        	president = await Repository.InsertPresidentsAsync(president);
            response.Data = president;
		}

		return response;
	}
}

Caso as regras de negocio sejam satisfeitas, o repositório é consumido.

Em nossos casos de teste, fazemos o mock no ultimo nível de infra estrutura, usando o NSubstitute para realizar o mock da interface IWhiteHouseRepository.

Cada teste executado no cenário acima será de forma reproduzido de forma isolada.