O acesso padrão não torna o modificador de acesso privado redundante.
A posição dos designers de idiomas é refletida no tutorial oficial - Controlando o acesso aos membros de uma classe e é bastante claro (para sua conveniência, declaração relevante na citação em negrito ):
Dicas para escolher um nível de acesso:
Se outros programadores usarem sua classe, você deseja garantir que erros de uso indevido não ocorram. Os níveis de acesso podem ajudá-lo a fazer isso.
- Use o nível de acesso mais restritivo que faça sentido para um membro específico. Use privado, a menos que tenha um bom motivo para não fazê-lo.
- Evite campos públicos, exceto constantes. (Muitos dos exemplos do tutorial usam campos públicos. Isso pode ajudar a ilustrar alguns pontos de maneira concisa, mas não é recomendado para o código de produção.) Os campos públicos tendem a vincular você a uma implementação específica e limitar sua flexibilidade na alteração do código.
Seu apelo à testabilidade como justificativa para descartar completamente o modificador privado está errado, como evidenciado, por exemplo, pelas respostas em Novo no TDD. Devo evitar métodos privados agora?
Claro que você pode ter métodos particulares e, claro, pode testá-los.
Existe alguma maneira de executar o método privado; nesse caso, você pode testá-lo dessa maneira ou não há como executar o privado, nesse caso: por que diabos você está tentando testá-lo, apenas excluir a coisa maldita ...
A posição dos designers de idiomas sobre a finalidade e o uso do acesso no nível do pacote é explicada em outro tutorial oficial, Criando e usando pacotes e não tem nada em comum com a ideia de eliminar modificadores privados (para sua conveniência, declaração relevante na citação em negrito ) :
Você deve agrupar essas classes e a interface em um pacote por vários motivos, incluindo o seguinte:
- Você e outros programadores podem determinar facilmente que esses tipos estão relacionados ...
- Você pode permitir que tipos dentro do pacote tenham acesso irrestrito um ao outro e ainda assim restringir o acesso a tipos fora do pacote ...
<BR> "Acho que ouvi o suficiente choramingando. Acho que está na hora de dizer alto e claro ...">
Métodos particulares são benéficos para o teste de unidade.
A nota abaixo pressupõe que você esteja familiarizado com a cobertura do código . Caso contrário, reserve um tempo para aprender, pois é bastante útil para os interessados em testes de unidade e em todos os testes.
Tudo bem, então eu tenho esse método privado, testes de unidade e análise de cobertura me dizendo que há uma lacuna, meu método privado não é coberto por testes. Agora...
O que eu ganho ao mantê-lo privado
Como o método é privado, a única maneira de prosseguir é estudar o código para aprender como ele é usado por meio de API não privada. Normalmente, esse estudo revela que o motivo da lacuna é que um cenário de uso específico está ausente nos testes.
void nonPrivateMethod(boolean condition) {
if (condition) {
privateMethod();
}
// other code...
}
// unit tests don't invoke nonPrivateMethod(true)
// => privateMethod isn't covered.
Por uma questão de integridade, outras razões (menos freqüentes) para essas lacunas de cobertura podem ser erros na especificação / design. Não vou me aprofundar nisto aqui, para manter as coisas simples; basta dizer que, se você enfraquecer a limitação de acesso "apenas para tornar o método testável", perderá a chance de descobrir que esses erros existem.
Tudo bem, para corrigir a lacuna, adiciono um teste de unidade para o cenário ausente, repito a análise de cobertura e verifico se a lacuna desapareceu. O que eu tenho agora? Eu tenho como novo teste de unidade para uso específico de API não privada.
O novo teste garante que o comportamento esperado para esse uso não seja alterado sem aviso prévio, pois, se for alterado, o teste falhará.
Um leitor externo pode examinar esse teste e aprender como ele deve usar e se comportar (aqui, o leitor externo inclui o meu eu futuro, pois tenho a tendência de esquecer o código um mês ou dois depois de terminar).
Um novo teste é tolerante à refatoração (refatoro métodos privados? Você aposta!) O que eu fizer privateMethod
, sempre desejarei testar nonPrivateMethod(true)
. Não importa o que eu faça privateMethod
, não haverá necessidade de modificar o teste porque o método não é chamado diretamente.
Não é ruim? Pode apostar.
O que eu perco por enfraquecer a limitação de acesso
Agora imagine que, em vez de acima, eu simplesmente enfraqueci a limitação de acesso. Eu pulo o estudo do código que usa o método e prossigo diretamente com o teste que chama my exPrivateMethod
. Ótimo? Não!
Ganho um teste para uso específico da API não privada mencionada acima? Não: não havia teste para nonPrivateMethod(true)
antes e não existe agora.
Os leitores externos têm a chance de entender melhor o uso da classe? Não. - Ei, qual é o objetivo do método testado aqui? - Esqueça, é estritamente para uso interno. - Opa.
É tolerante a refatoração? De jeito nenhum: o que quer que eu mude exPrivateMethod
, provavelmente quebrará o teste. Renomeie, mescle com outro método, altere argumentos e teste parará de compilar. Dor de cabeça? Pode apostar!
Resumindo , aderir ao método privado me traz um aprimoramento útil e confiável nos testes de unidade. Por outro lado, o enfraquecimento das limitações de acesso "para testabilidade" só me fornece um código de teste obscuro e difícil de entender, que também corre o risco permanente de ser quebrado por qualquer refatoração menor; francamente, o que recebo parece suspeito como dívida técnica .
</rant>