Alura > Cursos de Programação > Cursos de > Conteúdos de > Primeiras aulas do curso Testes de Integração em Java: Garantindo Qualidade em Back-ends Modernos

Testes de Integração em Java: Garantindo Qualidade em Back-ends Modernos

Boas Práticas de Testes - Apresentação

Apresentando o instrutor e o curso

Boas-vindas ao curso de testes de integração Java. Meu nome é Rodrigo Desordi e, por motivos de acessibilidade, vou me autodescrever.

Audiodescrição: Rodrigo é um homem branco, com cabelos loiros, usa óculos e possui um cavanhaque. Ele veste uma camiseta preta e está no estúdio da Alura.

Possuo 12 anos de experiência com Java e desenvolvimento de sistemas, atuando no mercado financeiro. Este curso é voltado para um perfil profissional intermediário a avançado, portanto, é necessário já ter conhecimento em Spring Boot e Containers.

Explicando a estrutura e os recursos do curso

Neste curso, teremos um ponto de partida inicial com o material fornecido na plataforma. Podemos fazer o download do projeto e seguir a estrutura proposta. Teremos um projeto já pronto, e a ideia do curso é criarmos a parte de testes de integração e testes de unidade. Toda a parte de implementação em Java está disponível no material.

Aproveitem também os recursos da plataforma. Além dos vídeos, temos atividades de apoio, conteúdos extras e o suporte do fórum e da comunidade para qualquer tipo de dúvida.

Vamos estudar?

Boas Práticas de Testes - Conhecendo o JUnit 5

Introduzindo o JUnit 5

Nesta aula, vamos explorar o JUnit 5, conhecer novos conceitos e uma nova estrutura para organizar nosso código. Nosso objetivo é desenvolver um processo de desenvolvimento de testes, otimizar nossos testes e reaproveitar código.

Analisando as melhorias do JUnit 5

Estamos analisando uma nova ferramenta, o JUnit 5, que substitui o JUnit 4, anteriormente utilizado para realizar testes em Java. O JUnit 5 já está disponível há algum tempo e traz diversas atualizações significativas. Ele melhora a comunicação com as IDEs, gera relatórios de cobertura de código de forma mais eficiente e apresenta um desempenho superior. Além disso, centraliza todas as novidades e oferece várias ferramentas que nos ajudam a organizar melhor nossos testes.

Boas Práticas de Testes - Arquitetura do projeto

Analisando a arquitetura hexagonal

Vamos analisar a arquitetura de sistemas da arquitetura limpa. Temos aqui uma referência da Alura que apresenta um desenho demonstrando a arquitetura hexagonal, que é derivada da arquitetura limpa. Vou explicar um pouco sobre como essa arquitetura impacta a maneira como organizamos nosso código e, consequentemente, nossos testes. Por isso, é importante entender a arquitetura aplicada em nosso projeto.

Na arquitetura hexagonal, à esquerda, temos nossas entradas, que podem ser interfaces web, interfaces móveis ou algum sistema externo, como gRPC ou outras APIs que se conectam ao nosso sistema. Tudo isso é acessado via adaptadores ao nosso núcleo, que é representado por um hexágono mais interno. Esse núcleo contém todas as nossas classes de negócio, entidades e classes de domínio centralizadas. O modelo é agnóstico, ou seja, não possui dependência com frameworks, permitindo que a estrutura Java seja levada para outras estruturas, mantendo o sistema desacoplado.

Explicando a estrutura de portas e adaptadores

A disponibilização para as camadas de entrada é feita via portas, que podem ser interfaces ou classes abstratas. Também temos as portas de saída, que integram com a infraestrutura, como bancos de dados, buckets ou publicação em message brokers em filas. Toda a estrutura é feita via adaptadores, especificando como devemos proceder.

Vou apresentar um modelo de implementação que segue esse conceito. Nesta estrutura, temos algo semelhante, onde todo o projeto está no framework do Spring. À esquerda, temos uma camada chamada application, que possui as responsabilidades de cada componente. Estão detalhados os Java Beans e POJOs que trafegam nossos dados. Temos os mappers que traduzem esses detalhes para nossas entidades, encontradas na camada do núcleo.

Descrevendo a camada de domínio e suas funções

Também temos o API Rest Server, que é o Rest Controller, com a descrição de que seria o controle clássico para receber as entradas. Existem os listeners para mensageria e um batch para representação. Na camada de domínio, guardamos nossos casos de uso, que podem ser serviços e negócios, dependendo da nomenclatura. A ideia é a mesma: onde colocamos nossas características de negócio ou features. A entidade, nesse modelo, representa tanto o ORM quanto nosso modelo de domínio.

Neste modelo, temos uma implementação que não segue estritamente a arquitetura limpa, pois trazemos algumas anotações para dentro dessa camada. Vamos analisar o código e discutir os prós e contras desse formato.

Utilizando repositórios e injeção de dependência

Aqui, utilizamos repositórios. Em vez de termos portas e adapters (adaptadores), temos uma interface que representa as portas e os adaptadores. Com isso, conseguimos aplicar a inversão de controle e usar a injeção de dependência do nosso framework para seguir esse modelo.

À direita, temos uma separação de uma camada chamada "infra". Essa camada também guarda details (detalhes) e messages (mensagens), mas agora em um formato de saída. Quando enviamos dados para uma fila ou integramos via API, são apenas representações de saída. Os mappers (mapeadores) traduzem a entidade para os DTOs e mensagens de saída. As implementações das interfaces permitem utilizar a inversão de controle. Em alguns casos, pode ser uma implementação concreta; em outros, apenas uma extensão. Essa extensão é importante para centralizar os testes, mesmo que não seja estritamente necessária.

Planejando a estrutura do projeto com Maven

Teremos componentes de integração com APIs, sejam internas ou externas, e publishers (publicadores) para enviar dados para uma fila. Este é o planejamento de como estruturaremos nosso projeto. Vamos abrir o IntelliJ para visualizar como essa estrutura multimódulo do Maven ficará.

Aproveitamos uma funcionalidade do Maven para evitar falhas humanas. É comum ver projetos únicos sem essa separação, mas, para fins didáticos, trabalharemos com um projeto raiz que serve como um bom parent (pai). Na linha 16, vemos que ele é um packaging (empacotamento) pom, o que significa que não possui classes de código-fonte, mas dá suporte a outros módulos.

<packaging>pom</packaging>

Esse trecho de código define que o projeto principal é um empacotamento do tipo POM, o que significa que ele não contém código-fonte diretamente, mas serve como um contêiner para outros módulos.

Definindo módulos no projeto Maven

Os módulos definidos que herdarão estão declarados a partir da linha 27. Temos a separação, conforme planejado, em domínio, infraestrutura e aplicação.

<modules>
    <module>domain</module>
    <module>infra</module>
    <module>application</module>
</modules>

Com essa estrutura, restringimos o acesso entre classes de diferentes módulos, evitando erros humanos e aumentando a segurança. A declaração dos módulos no POM permite que cada um deles seja tratado como um projeto separado, mas ainda assim parte do projeto principal.

Acredito que isso resume o que discutimos.

Sobre o curso Testes de Integração em Java: Garantindo Qualidade em Back-ends Modernos

O curso Testes de Integração em Java: Garantindo Qualidade em Back-ends Modernos possui 384 minutos de vídeos, em um total de 52 atividades. Gostou? Conheça nossos outros cursos de em Programação, ou leia nossos artigos de Programação.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Escolha a duração do seu plano e aproveite até 44% OFF

Conheça os Planos para Empresas