ArchUnit - Teste a sua Arquitetura Java
É indiscutível a importância dos testes unitários/automatizados em projetos e como ele pode prevenir possíveis erros futuros e manter a qualidade de código, garantindo que sua aplicação continue funcionando após alguma alteração em seu código. Além dos testes que estamos familiarizados, é possível também criar testes para Arquitetura do Projeto utilizando a ferramenta ArchUnit.
Seguindo esses princípios, conseguimos manter a organização da arquitetura do projeto, tornando mais legível de entender do que se trata cada classe, pasta e pacote, facilitando a entrada e adaptação de novos desenvolvedores no projeto.
ArchUnit é uma biblioteca gratuita e simples para testar a arquitetura do seu código Java usando qualquer framework, se o seu código respeita os padrões dos projetos, como por exemplo, um modelo MVC (model-view-controller). Ou seja, é possível verificar dependências de pacotes, classes, camadas, pastas, etc. Também existe suporte para as linguagens .NET/C#.
Para mais informações acesse o site: https://www.archunit.org/
Configuração
● Passo 1:
Primeiramente é necessário instalar a dependência maven ou gradle dele no seu projeto, é possível encontrar a última versão da dependênia no site MVN Repository: https://mvnrepository.com/artifact/com.tngtech.archunit/archunit
Após isso, cole a dependência abaixo em seu projeto Maven, no arquivo pom.xml:
<dependency>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit</artifactId>
<version>0.23.1</version>
<scope>test</scope>
</dependency>
Se for projeto Gradle, cole no arquivo build.gradle:
dependencies {
testImplementation 'com.tngtech.archunit:archunit:0.23.1' }
● Passo 2:
Após a IDE instalar as dependências e buildar o projeto, já é possível iniciar os testes. Neste exemplo estaremos trabalhando com o projeto Spring Boot, onde utilizamos a biblioteca em nosso projeto e explicaremos melhor nossa estrutura de pastas e classes para realização de alguns testes.
Bem, segundamente criaremos nossa classe de teste, chamada “ArchitectureTest”. Note que só é necessário uma anotação do spring “@SpringBootTest”, não será necessário mockar ou acessar base de dados. Neste primeiro exemplo iremos explicar a estrutura de código do ArchUnit que é bem simples de usar, siga o exemplo da imagem abaixo:
No método de teste criado chamado “testArchitetureRules()”, temos os seguintes passos:
1. JavaClasses importedClasses = new
ClassFileImporter().importPackages("br.org.sesisc.smart.controllers"); 1
Importação das classes dentro de um package (Pasta). Na função “importPackages” informamos o caminho que queremos extrair das classes, neste caso “br.org.sesisc.smart.controllers”. Com a variável “importedClasses” conseguimos extrair informações gerais de classe, como por exemplo: nome da classe, tipo de acesso modificador (private, public e protected), anotações utilizadas, caminho, tipo de classe (Interface, Enum), pacotes javas, entre outros.
2. ArchRule rule = classes()...
São as regras de testes, quais são as classes filtradas e quais são as condições que serão testadas nas classes. Aqui existem inúmeras possibilidades que podem se definir com base em seu projeto. A seguir alguns exemplos básicos de “ArchRule”:
Exemplo 1: Controllers
Neste exemplo estamos realizando os testes em todas as classes dentro da pasta controllers do projeto. Primeiramente, devemos seguir com o método “classes().that()” e dizer quais classes eles irão filtrar. Neste caso, “.areAnnotatedWith(RestController.class).and().haveSimpleNameNotStartingWi
th(“Generic”)” irá filtrar apenas classes que tem anotação “@RestController” e que não comece com nome “Generic”.
Em seguida continuamos a lógica com “.should()” definindo as lógicas de testes que a classe deverá respeitar. Neste caso, “beAnnotatedWith(RequestMapping.class).andShould().bePublic().andShould() .haveSimpleNameEndingWith(“Controller”);” (pode ser utilizado “orShould()” também) que irá testar se estas classes têm anotação obrigatória “@RequestMapping”, se são públicas e se terminam com “Controller”. Com isso, temos a lógica pronta para as classes Controllers. Veja abaixo o padrão da classe “Controller” que deve ser respeitada:
Exemplo 1: UserController
Exemplo 2: Services
Neste exemplo iremos filtrar classes dentro do pacote “services” que tenham a anotação “@Service” e que não começam com nome “Generic”. Será testado ainda se estas classes são públicas e terminam com nome “Service” ou “ServiceImpl”. Com isso, temos a lógica pronta para as classes Services. Veja abaixo o padrão da classe Service que deverá ser respeitada:
Exemplo 2: ParamService
3. rule.check(importedClasses);
Realiza o teste final em todas as classes importadas com base nas regras criadas anteriormente. A parte final, onde dirá se seu projeto está ou não respeitando os padrões propostos dentro dos testes.
● Passo 3:
Execute os testes na classe criada, no nosso caso “ArchitectureTest.class”. Caso seu projeto esteja respeitando os padrões estabelecidos nas regras do ArchUnit, o teste terá êxito conforme abaixo:
Caso alguma classe fuja do padrão, como: nome incorreto, pasta incorreta, falta de anotação, entre outros, o teste falhará e informará qual classe está incorreta para correção. Como mostra o exemplo abaixo de uma classe incorreta:
Neste exemplo, renomeie erronea e propositalmente a classe “ProfileController.java” para “ProfileControl.java”. Veja que o teste unitário rapidamente detectou o erro dizendo o seguinte: “br.org.sesisc.smart.controllers.profiles.ProfileControl does not end with 'Controller' ”, indicando que a seguinte classe não termina com nome “Controller” (ProfileControl) e portanto deverá ser corrigida. Os testes unitários ArchUnit funcionam desta forma, detectando falhas que fujam do escopo da arquitetura do projeto, seja classes e pacotes incorretos ou uma classe fora de sua respectiva pasta, entre outras possibilidades.
Conclusão
A biblioteca ArchUnit entrega uma série de funções para serem utilizadas para cada proposta, basta analisar qual melhor atende às suas necessidades e adequar seu código corretamente. Para mais informações de como utilizar, siga a documentação do ArchUnit: https://www.archunit.org/userguide/html/000_Index.html#_introduction
Neste artigo usamos alguns exemplos utilizando SpringBoot, respeitando as anotações e o padrão de nome de classes usada no framework. Inclusive, já estamos começando a adoção do ArchUnit em nossos projetos para manter a qualidade da arquitetura do projeto para que os demais desenvolvedores saibam e respeitem os padrões propostos.