quarta-feira, 19 de dezembro de 2007

Como testar um Método Privado?

Pra começar, surgem duas perguntas:

Devo Fazer? Como devo fazer?

A primeira resposta é: Claro que sim, se ele pode quebrar, ele deve por motivo óbvios, e se não pode quebrar, ele deve por motivos estratégicos.

A segunda resposta é: Aí depende. Depende da linguagem, da capacidade do desenvolvedor, do tempo, "beleza" do código, facilidade de manter, etc.

Pra tentar deixar mais claro, vamos considerar duas possibilidades:

- Testar Explicitamente o método privado;
- Testar por intermédio de outro método.

A primeira possibilidade, testar explicitamente, pode-se fazer duas coisas (que me vem a mente, mas podem existir outras):

- Você pode trocar a visibilidade do método para public com Reflection, em tempo de execução;
- Alterar o método para protected. Isso é mais complicado, em casos de código legado ou sistemas de outros.

A segunda possibilidade, a que prefiro, é usar outro método "testável" para testar o método privado.

Na prática, é muito fácil perceber isso, mas vai que você quer entender logo o que estou falando, então vai um exemplo:


Tenho uma classe com um método public (que retorna uma String) e um private, o método private (criptografa a palavra blablabla)

 0: public class ClassePeba {
1: public String getAlgo(int i)
2: {
3: String palavra = "blablabla";
4: palavra = criptografaPlavra(palavra, i);
5: return palavra;
6: }
7:
8: private String criptografaPalavra(String palavra,
9: int i) {
10: if(i == 1)
11: {
12: palavra = palavra.replace("a", "@");
13: palavra = palavra.replace("b", "!");
14: palavra = palavra.replace("l", "?");
15: }else{
16: palavra = palavra.replace("a", "*");
17: palavra = palavra.replace("b", "$");
18: palavra = palavra.replace("l", "%");
19: }
20: return palavra;
21: }
22: }
O método private (criptografaPalavra) será testado por intermédio do método public getAlgo
Veja os comentários no código:
 0: public class TestClassePeba {
1:
2: ClassePeba classePeba;
3:
4: @Before
5: public void prepare()
6: {
7: classePeba = new ClassePeba();
8: }
9:
10: @Test
11: public void testGetAlgo()
12: {
13: //fazendo este teste, o método getAlgo
14: //já está 100% coberto
15: assertEquals("!?@!?@!?@", classePeba.
16: getAlgo(1));
17: //fazendo este teste, o método
18: //criptografaPalavra também fica 100% coberto
19: assertEquals("$%*$%*$%*", classePeba.
20: getAlgo(2));
21: }
22: }
Acho que fica claro o motivo pelo qual, considero esta abordagem a mais indicada, ela é mais simples, fácil de implementar e de manter, e não a considero nem um pouco deselegante.

ps. Por favor, não reparem o método de criptografar, criei só pra demonstração.