DEV Community

Cover image for Testes Arquiteturais - Padronize já a arquitetura do seu projeto!
Gabriel Augusto Morato dos Santos
Gabriel Augusto Morato dos Santos

Posted on • Edited on

Testes Arquiteturais - Padronize já a arquitetura do seu projeto!

Introdução

image

Muita das vezes quando iniciamos um projeto, a maior dificuldade que possuímos é no momento de fazer a organização entre os nossos pacotes, classes e definições de qual classe poderá ter acesso a determinada outra classe, após derrotarmos essa dificuldade, o nosso próximo desafio é mantermos essa organização e documentarmos para os futuros desenvolvedores ou até mesmo nós, como definimos a arquitetura do nosso projeto, isso é o que você irá ver a seguir!

Por quê Testes Arquiteturais?

image

Como foi dito anteriormente, além de organizarmos mais o nosso projeto e definirmos uma convenção, conseguimos ter uma documentação de uma forma bem amigável,conforme exemplo visto abaixo, vimos uma regra informando onde as classes anotadas com Entity deverão residir:

@ArchTest
    static final ArchRule entities_must_reside_in_a_domain_package =
            classes().that().areAnnotatedWith(Entity.class).should().resideInAPackage("..domain..")
                    .as("Entidades deverão residir no pacote de domínios");
Enter fullscreen mode Exit fullscreen mode

Mas que tal agora colocarmos a mão na massa? :)

Quais tecnologias iremos utilizar?

image

Para esse artigo em questão, iremos precisar ter as seguintes tecnologias no nosso projeto:

  1. Java 8+: Linguagem de Programação Java na versão 8+
  2. Maven: Ferramenta para o gerenciamento de dependências no Java.
  3. ArchUnit: Ferramenta que será utilizada para o desenvolvimento dos nossos testes arquiteturais
  4. Spring: Framework de programação

Não irei entrar muito adentro de todas as tecnologias utilizadas pois não é o nosso objetivo desse artigo.

Configurando o nosso projeto:

image

Para que possamos utilizar o archunit no nosso projeto, será necessário adicionarmos a seguinte dependência:

<dependency>
    <groupId>com.tngtech.archunit</groupId>
    <artifactId>archunit-junit5</artifactId>
    <version>0.18.0</version>
    <scope>test</scope>
</dependency>
Enter fullscreen mode Exit fullscreen mode

Após isso, iremos fazer uma criação de uma única classe chamada ArchitectureTest no nosso pacote de testes, no qual irá ter a seguinte implementação nesse primeiro momento:


@AnalyzeClasses(
        packages = "SeuPacote",
        importOptions = ImportOption.DoNotIncludeTests.class
)
public class ArchitectureTest {
}
Enter fullscreen mode Exit fullscreen mode

Observação: No exemplo acima, foi inserido uma opção para que não incluísse os testes na nossa validação, mas caso você queira definir um padrão no nome dos seus testes também, pode ficar à vontade. :)

Agora sim, vamos ao que nos interessa! =D

image

Juntos, iremos definir uma arquitetura simples na qual iremos ter classes de Controller que irão poder chamar apenas as classes Service e que poderão chamar somente classes Repository, conforme visto no desenho abaixo:

image

Após isso, iremos definir como irá ficar o nome de cada classe e por último, qual será o pacote que a mesma irá residir, dito isso, vamos criar a nossa arquitetura? :)

Definindo o nome das nossas classes:

image

No 1º passo iremos definir como deverá ser o nome das nossas classes, já que somos pessoas extremamente criativas, vamos utilizar o nome de cada anotação no final da nossa classe, porquê será que ninguém nunca pensou nisso antes? :D

    @ArchTest
    static ArchRule ClassesQuePossuemAnotacaoController_DeveraoFinalizarComNomeController =
            classes()
                    .that().areAnnotatedWith(Controller.class)
                    .should().haveSimpleNameEndingWith("Controller")
            .as("Caro desenvolvedor, todas as nossas classes que estão anotadas como Controller, deverão ter o nome finalizado com Controller");
Enter fullscreen mode Exit fullscreen mode

Como visto acima, o uso dos testes do ArchUnit são bem simples e bastante intuitivos, dentro do nosso teste estamos informando que toda classe que está anotada como Controller, deverá ter o nome finalizado como Controller e além disso deixamos uma dica para o próximo desenvolvedor que não fizer da forma que nós planejamos, utilizando o ".as(....)", isso não é legal? :)

Forcei um erro, mudando o nome da nossa classe para UsuarioJoao, olha que legal o que aconteceu:

image

Após isso, basta criarmos as regras para as nossas outras classes, mas isso agora eu deixo para você tentar :)

Caso não consiga não se preocupe, basta abrir o GitHub do projeto :)

Definindo a residência das nossas classes:

image

No 2º passo iremos definir onde cada classe irá residir, o teste irá ser bastante similar ao anterior, então vamos lá? :)

@ArchTest
    static ArchRule ClassesQuePossuemAnotacaoController_DeveraoResidirNoPacoteController =
            classes()
                    .that().areAnnotatedWith(Controller.class)
                    .should().resideInAPackage("..controller..")
                    .as("Caro desenvolvedor, todas as nossas classes que estão anotadas como Controller, deverão residir no pacote *.controller");
Enter fullscreen mode Exit fullscreen mode

Com o exemplo acima, informamos no ".resideInAPackage(...)", qual será o local que a nossa classe de fato irá residir.

Definindo qual classe irá chamar qual classe:

image

Por último, para concluirmos o nosso desafio, precisamos definir qual classe irá chamar a outra, para que dessa forma, tenhamos o controle de qual classe poderá conhecer a outra, para isso iremos seguir o exemplo abaixo:


 @ArchTest
    static final ArchRule ClassesQueResidemNoPacoteControllerNaoPodemConhecerRepository =
            noClasses().that().resideInAPackage("..controller..")
                    .should().dependOnClassesThat().resideInAPackage("..repository..")
            .as("As classes Repository não podem ficar juntas das classes Controller :(");

Enter fullscreen mode Exit fullscreen mode

No exemplo acima, definimos que nenhuma classe que resida no pacote Controller poderá depender de nenhuma classe que resida no pacote Repository, que história triste de amor, não? :D

Obrigado pessoal =D

image

Agradeço a todos vocês que leram o meu artigo e que me acompanham na criação dos meus conteúdos :)

O ArchUnit, possui uma ótima documentação e me ajuda muito nos projetos que executo no meu dia à dia, o que você acha de apresentar isso nos seus projetos? :)

Top comments (2)

Collapse
 
pedrogabrielsantoslima profile image
pedrogabrielsantoslima

Vai ajudar bastante, muito bom xD

Collapse
 
gabrielaugusto1996 profile image
Gabriel Augusto Morato dos Santos

Show de bola Pedro! Fico feliz que tenha gostado =D