Skip to content
janeiro 24, 2011 / cassiomarques

Porque não se deve testar métodos privados

Esta é uma pergunta frequente:

– Devo testar meus métodos privados?

E minha resposta é sempre a mesma:

– Não.

Aliás, essa é a resposta que muitas pessoas darão à pergunta acima. Mas porque raios não é uma boa idéia testar métodos privados?

Considere o fluxo básico do TDD:

  1. Escreva um caso de teste
  2. Assista o teste falhar (ok, eu raramente sigo esta etapa, vou direto prá próxima)
  3. Escreva o código mais simples possível capaz de fazer o teste passar.
  4. Refatore, se for o caso.
  5. Repita para novos casos de teste, até que sua mente cruel não seja capaz de criar novas formas de sacanear seu código.

Definir métodos como privados é algo que faz parte do processo de refatoração. Um método não deve nascer como privado pura e simplesmente. Na maioria das vezes, se você começa a escrever a implementação que faz um teste passar definindo métodos como privados, você está pensando demais. Ou seja, está se concentrando em detalhes de implementação e deixando o comportamento em segundo plano. Lembre-se: você deve inicialmente escrever o código mais simples possível capaz de fazer o teste passar. Ou seja, não esquente a cabeça em escrever o código mais elegante do mundo logo de cara. Escreva algo simples e até mesmo feio, mas que você seja capaz de compreender e que faça o teste passar, ou melhor, que implemente o comportamento esperado. Após isso feito, identifique pontos de possível refatoração. Geralmente, extrair métodos a partir de trechos de código repetidos leva à criação de métodos privados.

Outro efeito negativo de se testar métodos privados é que os mesmos estão frequentemente sujeitos a mudarem ou até mesmo desaparecem. Conforme seu código evolui e mais refatorações são realizadas, muitos métodos privados podem não fazer mais sentido, o que fará com que você tenha um monte de testes quebrados, inúteis e que não refletem a realidade.

Por fim, lembre-se que além de testar o comportamento do seu código, testes unitários podem ser utilizados como documentação executável. Assim como ocorre com a documentação escrita através de comentários especiais no código (como feito com o Rdoc, Javadoc, etc), você não deve exportar documentação que contenha métodos privados, pois os mesmos são detalhes de implementação e não devem ser acessados diretamente. Infelizmente muitos programadores não são suficientemente educados e, se você mostrá-los como, eles vão invadir as entranhas de seus objetos e usar coisas como my_object.send(:some_private_method). Além disso, incluir métodos privados na documentação só faz com que a mesma seja mais bagunçada e difícil de consultar.

No fim das contas, seus métodos privados estarão sendo testados, mas indiretamente. Eles não são o objetivo final, mas sim apenas um meio, uma etapa na execução do método sendo testado. Este última sim é importante, pois provavelmente faz parte da API pública do seu objeto.

10 Comentários

Deixe um comentário
  1. Celestino Gomes / jan 24 2011 4:30 pm

    My 1 cent!

    Bom, em alguns dos projetos por onde passei, nem todo código estava coberto por testes, diversas equipes não tinham como prática TDD, outras de escrever testes depois do comportamento estar funcionando e, claro, no processo de refatoração, na tentativa de deixar um método público mais simples de ler, muitas vezes se extrai métodos que acabam se tornando privados, pois são auxiliares ao de onde foi extraído e, dependendo da complexidade do mesmo. Em casos que um método público não nasceu do TDD, mas digamos com algum teste para ele e o mesmo sofreu a refatoração para deixar o código mais limpo, existem muitas chances de que todos os testes possíveis e imagináveis não foram escritos para cobrir os resultados do mesmo. Isso também não quer dizer que com TDD tenhamos escrito todos os testes possíveis e imagináveis.

    Enfim, minha resposta é: Se você acha que deve, porque não?

    • cassiomarques / jan 24 2011 4:39 pm

      Tino,

      Se entendi bem seu comentário, você fala sobre o caso onde o código já está escrito e testes são criados posteriormente, para aumentar a cobertura. Neste caso eu acho que ainda assim os testes devem ser escritos tendo como “alvo” a interface pública. Ela é o ponto de entrada da lógica sendo testada. Se para fazer o teste passar você vai mexer em um método privado, isso é um detalhe de implementação, um efeito colateral da estrutura do código. Para mim, o teste deve simular um usuário do código e pelo menos em situações normais objetos devem ser sempre acessados por sua interface pública.

      Não sei se era esse o ponto que você quis discutir :)

      • Celestino Gomes / jan 24 2011 4:49 pm

        Sou do mesmo pensamento que os testes devam ser somente dos métodos públicos, pois é por eles que vão entrar as informações externas a aplicação para processamento.

        Mas nada impede de testar os métodos privados. Vai ser overhead? Pode ser, mas não mata ninguém… :D

  2. PotHix / jan 24 2011 5:13 pm

    Æ!!

    Eu tenho a mesma opinião do Tino.
    Eu acho que devemos testar as interfaces publicas, mas testar métodos privados não vai ser um grande problema também.

    Acho que esse comentário é mais para dizer: “Não siga isso como regra”, mas considere quando você estiver desenvolvendo.

    É a mesma coisa que dizer: “Não use mocks!”, ao invés de “Use mock quando realmente for necessário usar”. :)

    Há braços

    • cassiomarques / jan 24 2011 6:50 pm

      Opa,

      Vendo *somente* por esse lado, sim, pode ser overhead mas não mata ninguém. Mas vendo pelo fluxo do TDD bem como pelo fato de sua documentação executável ficar poluída com detalhes de implementação que não fazem parte da interface pública (e assim não deveriam ser consultados, usuário do seu código nem deveria saber que existe). Além disso os testes serão mais frágeis. Se testassem somente comportamento, você poderia mudar a implementação e os testes deveriam continuar passando sem alterações. Se seus testes estiverem acoplados a métodos privados, é muito provável que alterações no código que não alteram comportamento quebrem seus testes.

      Abraço!

      • PotHix / jan 24 2011 7:29 pm

        Æ!!

        Sim, claro! Eu entendo o seu ponto.
        O que eu quis dizer é que cada caso é um caso, e é meio complicado dizer: “Não faça isso”, por que sempre tem algum caso que isso é útil, apenas tome algo como base.

        Há braços

  3. guilhermesilveira / mar 28 2011 9:23 pm

    A comunicação com um objeto é feita através de sua interface pública: em Ruby são seus métodos públicos e as “constantes”. Testar qualquer outra coisa é quebrar encapsulamento.
    Mas ai pode surgir o argumento de que o teste é necessário (= dizer que quebrar o encapsulamento será necessário).
    Se o método é privado, e não é acessado por nenhuma interface pública, ele é inutil e pode ser apagado.

    Isso significa que o método privado é acessado pro alguma interface pública. Se você fizer os testes para a interface pública corretamente, estará testando os branches do método privado.
    Isto é, será inutil criar um teste para o método privado, pois o teste do metodo publico ja cobriu esses casos.

    Um argumento comum é dizer que seria dificil cobrir todos os branches, pois o metodo publico tem diversas combinações x combinações do privado = muitas * muitas = muito mais do que muitas combinações.

    Extraia método para composite e teste separadamente. Principalmente pq se o método faz muita coisa, e num contexto diferente (afinal, ele foi extraido) é pq ele não é do seu objeto, ele pertence a outro escopo, outro lugar. Extraia. Novamente, sem necessidade de testar metodo privado.

    Por consequencia, a necessidade de testar metodo privado indica um design OO quebrado: seu objeto tem muita responsabilidade ou seu metodo (pub+pri) é muito complexo.

    Abraço

  4. guilhermesilveira / mar 28 2011 9:25 pm

    ps: outra abordagem lógica muito próxima: http://www.aniche.com.br/2010/11/voce-quer-testar-metodos-privados-certeza/

    ps2: me esqueci, muito bom o post… concordo completamente, claro.

  5. Pércio / mar 21 2013 4:43 pm

    Cara! Muito bom mesmo, parabéns pela clareza e riqueza de informação!

Trackbacks

  1. /*Codificando*/ :: Porque não se deve testar métodos privados | Ruby Here Blog

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: