Árvore de páginas

Versões comparadas

Chave

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

Índice

O Construímos o TNF foi construído voltado para que a as boas praticas e os princípios de um código limpo fossem respeitados.

Para que isso aconteça um dos principais pontos a serem abordados aqui nesta seção são os testes de unidade e testes integrados.

Nesse tópico será descrito como realizar os testes de unidade, validando regra a regra de uma aplicação construída com o TNF também como os testes integrados passando de camada a camada de sua aplicação.

Frameworks

devemos construir um código que possibilite ser testado tentando obter o máximo de cobertura possível.

Vamos conhecer a estrutura que o TNF oferece para criação de nossos testes unitários e integrados.

Frameworks

O TNF prove algumas estruturas para realização de testes em sua aplicação. Não é uma regra, mas sugerimos os seguintes frameworks para utilização em seu projeto.

...

Framework open source, largamente utilizado para realizar testes na plataforma .NET. Ele que suporta todas as tecnologias, atualmente fazendo . Atualmente faz parte do .NET Foundation.

https://xunit.github.io/

...

Framework open source para realização de .NET mocking. Com ele é possível realizar mock de propriedades, classes, interfaces entre outras funcionalidades. 

Para sua utilização, basta realizar a instalação do pacote NSubstitute via interface nuget.

http://nsubstitute.github.io/

Shouldly

Framework com estrutura de asserção. Junto com o Xunit fornece uma gama de métodos de extensão para realizar os assert asserts e validações de regras, objetos e comportamentos.Para sua utilização, basta realizar a instalação do pacote Shouldly via interface nuget.

https://github.com/shouldly/shouldly

NSubstitute

Framework open source para realização de .NET mocking. Com ele é possível realizar mock de propriedades, classes, interfaces entre outras funcionalidades.

http://nsubstitute.github.io/

Cenário de testes

Para todos os testes descritos a seguir considere o seguinte cenário:

Todos os cenários descritos a seguir estão dispostos em nosso github no endereço: https://github.com/totvsnetcore/tnf-samples/tree/master/TnfSample-Architecture

...

Bloco de código
languagec#
firstline1
titlePresidentEntity.cs
linenumberstrue
[JsonObject("president")]
public class PresidentEntity : CarolEntity
{
	public string Name { get; set; }
    public string ZipCode { get; set; }
    public override object GetStagingMapping()
    {
    	return new
        {
        	name = "string",
            zipCode = "string"
        };
	}
}
 
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; }
}

Camada de Domínio

Nessa camada temos um serviço chamado Serviço WhiteHouseService responsável pela persistência das entidade de presidentes no Carol.

Esse serviço realiza a validação da entidade de domínio President, utilizando o padrão de builder do TNF com o uso de specifications.

Abaixo temos a implementação do serviço WhiteHouseService usando um repositório chamado IWhiteHouseRepositoriy implementado pela camada de infraestrutura consumindo dados do Carol.

Bloco de código
languagec#
firstline1
titleWhiteHouseService.cs
linenumberstrue
// Domain service interface
public interface IWhiteHouseService : IDomainService
{
    Task<DtoResponseBase<PresidentDto>> InsertPresidentAsync(PresidentDto request);
}
 
// Domain service
public class WhiteHouseService : DomainService<IWhiteHouseRepository>, IWhiteHouseService
{
    private readonly IEventBus _eventBus;
 
    public WhiteHouseService(IWhiteHouseRepository repository, IEventBus eventBus)
        : base(repository)
    {
        _eventBus = eventBus;
    }
 
    public Task<DtoResponseBase<PresidentDto>> InsertPresidentAsync(PresidentDto request)
    {
        var response = new DtoResponseBase<PresidentDto>();
        var builder = new PresidentBuilder()
            .WithId(item.Id)
            .WithName(item.Name);
 
        var build = builder.Build();
        if (!build.Success)
        {
            response.AddNotifications(build.Notifications);
            return response;
        }
 
        var presidentCreated = await Repository.InsertPresidentAsync(request);
        response.Data = presidentCreated;
 
        // Trigger event
        _eventBus.Trigger(new PresidentCreatedEvent(presidentCreated));
        return response;
    }
}

Como podemos observar no código acima quando é feita a inserção de um presidente através do serviço a estrutura de builder é consumido validando assim se a entidade pode ou não utilizar o repositório de dados no Carol.

Caso a entidade esteja apta a ser cadastrada os dados são persistidos e um evento de criação de um presidente é disparado.

Abaixo podemos conferir a estrutura de validação da entidade através de builder para a entidade President:Além da validação da entidade nosso caso de testes faz uso de Domain Events e dispara um evento após inserir a entidade de presidente.

Bloco de código
languagec#
firstline1
titlePresidentBuilder.cs
linenumberstrue
publicinternal class PresidentBuilder : Builder<President>
{
    public PresidentBuilder()
        : base()
    {
    }
    public PresidentBuilder(President instance)
        : base(instance)
    {
    }
    public PresidentBuilder WithId(string id)
    {
        Instance.Id = id;
        return this;
    }
    public PresidentBuilder WithName(string name)
    {
        Instance.Name = name;
        return this;
    }
    public override BuilderResponse<President> Build()
    {
        // Entity specifications
        var shouldHaveName = new PresidentShouldHaveNameSpecification();
 
        if (!shouldHaveName.IsSatisfiedBy(Instance))
        {
            var notificationMessage = LocalizationHelper.GetString(
                AppConsts.LocalizationSourceName,
                President.Error.PresidentNameMustHaveValue);
            Response.AddNotification(President.Error.PresidentNameMustHaveValue, notificationMessage);
        }
 
        return base.Build();
    }
}

...

Bloco de código
languagec#
firstline1
titleIWhiteHouseAppService.cs
linenumberstrue
public interface IWhiteHouseAppService : IApplicationService
{
	Task<PagingDtoResponse<PresidentDto>> GetAllPresidents(GellAllPresidentsRequestDto request);
    Task<PresidentDto> GetPresidentById(string id);
    Task<DtoResponseBase<List<PresidentDto>>> InsertPresidentAsync(List<PresidentDto> dtos, bool sync = true);
    Task<DtoResponseBase> UpdatePresidentAsync(PresidentDto dto);
    Task<DtoResponseBase> DeletePresidentAsync(string id);
}

Camada de Serviços

Agora é a hora de expormos toda a nossa arquitetura criada.

Para isso temos uma camada de serviços feita em AspNetCore com duas APIs:

...

  • GetAll
  • Get
  • Post
  • Put
  • Delete

Definida a estrutura de nosso cenário nos próximos tópicos vamos descrever como realizar os testes unitários e integradosAPI com padrão RESTful para os dois serviços de aplicação criados expostos com ASP NET Core.