Executando verificação de segurança...
-1

Uma coisa sobre testes em Java

Quando vou dar manutenção em um projeto, seja ela evolutiva ou preventiva, tenho que olhar para os testes que já foram implementados. Quero garantir que o processo de CI vai continuar funcionando depois das minhas alterações. Geralmente existe implementação e me deparo, geralmente com dois tipos de métodos:

  • public: um ou mais, mas poucos
  • private: um monte deles

Há algum problema nisso? Sim! Se existe somente um método público, ele orquestra todos os outros privados. Provavelmente os métodos privados fazem alguma integração, ou formatam alguma String, ou fazem transformações, enfim, inúmeras tarefas.

Happy Flow e Corner Case

Eu tenho dois termos na minha cabeça:

  • Happy Flow: o fluxo principal do algoritmo
  • Corner Case: os fluxos alternativos, exceções, etc...

No Happy Flow todas as integrações funcionam, todas as transformações são bem sucedidas, ou seja, tudo funciona, tudo vai bem.

Os Corner Cases ocorrem quando uma integração falha, uma transformação não é bem sucedida, faltam dados para formatar uma String, etc. Tudo de errado pode acontecer.

Mas, dependendo da quantidade de integrações, transformações, formatações, etc, a combinação para fazer testes pode ser grande. Vamos imaginar que um service, por exemplo, precisa fazer duas integrações, acessar um repositório, formatar três Strings e fazer cinco transformações.
(E existem combinações piores do que isso)

A quantidade de testes com tudo isso, é imensa. A quantidade de combinações pode ser gigantesca. Sei que podem estar pensando que seria melhor dividir as coisas em classes pequenas (e isso é o que eu pensaria), mas já está implementado assim.

O que fazer nesse caso?

Um pouco de OO

Você conhece Orientação à Objetos. Não perguntei, afirmei. Vamos ao que interessa.

Você conhece os modificadores de acesso:

  • public: membros que podem ser acessados a partir de uma instância de um objeto pelo operador de ponto: instance.member.
  • private: somente acessíveis dentro de uma mesma instância.
  • protected: membros privados, que podem ser acessíveis por herança e por instância no mesmo package.
  • default: sem uma palavra chave reservada, "confina" um membro a ser visível dentro de uma package, seja através de uma instância ou por herança.

Entenda membros de uma class como métodos (comportamentos) e atributos.

Enfim, o que isso tem a ver com testes? Quando implementamos um teste com JUnit, a classe de teste fica separada em um diretório, mas com a mesma estrutura de pacotes. Isso faz com que quando carregamos, o Classloader pensa que ambas as classes estão no mesmo pacote.

Se estão no mesmo pacote, então podemos utilizar do modificador protected ao invés do modificador private para os métodos de nossa classe. Assim podemos testar de maneira independente nossos métodos privados.

Converter tudo para protected

Mas, espera um pouco? Devemos traduzir tudo para protected? Não. Nem tudo, devemos ter bom senso. É claro que devemos ter um julgamento do que é melhor a fazer. Algumas coisas devem estar escondidas, devem ser internas. Outras podem expostas.

A cobertura de Corner Cases será mais fácil. A detecção de algum problema vai ser tranquila.
E ainda é possível testar resultados dos métodos privados pelos métodos privados. Por exemplo, se um método privado formata uma String e depois é utilizado na criação de um objeto em um método protected, essa formatação pode ser testada nesse método protected.

Conclusões

Em suma, como engenheiros de software ou programadores, temos que tomar cuidado com o nosso código. Não devemos encadear muitas chamadas à métodos privados, principalmente quando realizam integrações.

Código legado, deixado por programadores que só tinham preocupação em entregar tarefas, independendo da qualidade final do software, pode possuir essas falhas graves e que não tiveram devida atenção para serem refatorizados.

Aplicar SOLID, Orientação a Objetos e Design Patterns pode deixar o código mais limpo, legível e evitar essas más práticas.

Carregando publicação patrocinada...
1

Ou pode piorar o código. Seguir receitas de bolo, sempre pode criar problemas. Saber o que está fazendo por completo é o coreto e tende a dar melhores resultados.

Um exemplo que vejo muito é a dificuldade que criam em sistemas na parte que realmente fará algo de valor no sistema para facilitar os testes, ou seja, sujam o código, em geral por falta de domínio de todo o processo, de pensar como um engenheiro que cria uma solução sem estragar nada, e em alguns casos deficiências da tecnologia escolhida, o que já é um erro de engenharia que deverá ser compensado com complexidade ou aceitar a falha.

O que foi pensado acima parece uma aberração no sentido que acabei de falar.

Eu não domino Java, mas ser protected faz o método ser acessível no mesmo pacote? Não é só acessível em classes que herdam desta?

(depois me informaram que deixa acessível ao pacote, o que é algo bem estranho e usar uma misfeature da linguagem é pior ainda, ou seja, nem Java sabe OO e fere um dos pilares)

Eu não afirmo que "você" sabe OOP. Eu programo no paradigma há mais de 40 anos, só recentemente eu percebi como OOP realmente é e agora acho que entendo razoavelmente, mesmo assim tem falhas. O fato da maioria das pessoas acharem que sabe e eu vejo quando elas fazem ou falam sobre oi assunto eu sei que não sabem, é um indicativo que está longe da pessoa aprender OOP corretamente, provavelmente nunca acontecerá, porque eu sempre falo, quando você treina o erro é ele que fará para sempre.

Não se deve testar métodos privados, a não ser que tenha um motivo muito forte para isto, deve apensar ter um bom nível de cobertura testando os públicos, se fizer isso certo, os privados será colocados à prova.

Eu duvido que corner case é o termo aplicável no que foi definido.

S2


Farei algo que muitos pedem para aprender a programar corretamente, gratuitamente (não vendo nada, é retribuição na minha aposentadoria) (links aqui no perfil também).