sexta-feira, 27 de novembro de 2009

Guicifique seus Testes - Parte 1

Este artigo é primeira parte da tradução para português do interessante artigo Guicing Up Your Testing, June 21, 2007, por Dick Wall. Trata-se de uma leitura interessante, que junta dois tópicos que estou estudando atualmente: Teste Unitário e Google Guice, além de falar um pouco sobre Injeção de Dependências e os Padrões de Projeto Singleton e Factory.

Índice

Introdução

O Guice é um container leve para injeção de dependências escrito por Bob Lee e Kevin Bourrillion, da Google. Este artigo examina o caso de uso mais simples e óbvio do Guice, para simular (mock) ou imitar (fake) objetos em testes unitários.

Se você já é familiar com a idéia de Objetos Mock e Objetos Fake, este artigo pode parecer tedioso (exceto a parte do Guice, espero). Porém, se você ainda não utiliou estas técnicas, este artigo vai além de cobrir a sua utilização: vai demonstrar também como estas técnicas andam de mãos dadas com a injeção de dependências.

O Caso de Teste

Para ilustrar o uso do Guice, é necessário configurar um exemplo de teste unitário. Vou me basear em algo relativamente simples:

O sistema possui uma classe Pedido, que usa um Gerenciador de Taxas de Juros para verificar qual a taxa que incide sobre uma venda para um determinado Cliente. O pedido acrescenta o valor da taxa ao valor total dos Itens do pedido. A taxa varia de acordo com o status do cliente, então o gerenciador procura a taxa de um determinado cliente usando o seu ID. Vamos supor que o Banco de Dados onde essas taxas ficam armazenadas está sobrecarregado com muitos registros, e que leva 5 segundos para executar qualquer tipo de consulta ou atualização.

Seu objeto de testes se parecerá com isto:

Vamos dar uma olhada nesta implementação. Para o construtor, observe que:

O construtor está obtendo um objeto GerenciadorTaxasJurosBD usando o padrão Singleton, uma forma bastante comum em muitos softwares atuais. Este padrão assegura que, em toda a máquina virtual, haverá apenas um objeto deste tipo, e ele deve ser obtido através de uma chamada estática da classe GerenciadorTaxasJurosBD .

Eu pessoalmente acho que o padrão Singleton, pelo menos na forma como a maioria das pessoas o implementam (chamada estática que retorna um atributo privado interno a uma classe) é um dos mais nocivos padrões GoF (veja [http:://a.b.c livro da Gang of Four]), entre outros numerosos padrões de autoridades mundo afora. O perigo está no fato de que é muito fácil de entender, muito sedutor, mas resulta em conseqüências indesejáveis em muitos e diversos aspectos.

Neste caso em particular, a implementação de GerenciadorTaxasJurosBD na forma de um Singleton implica que, todas as vezes que você criar um Pedido, você está amarrado a uma implementação específica, a que se comunica com o Banco de Dados. Este é o problema com o Singleton: ele torna muito fácil recuperar o gerenciador de taxas que precisamos consumir, mas o preço que pagamos é que ficamos presos a uma implementação específica, com pouca flexibilidade para alterar a implementação.

Por exemplo, quando você quiser testar esta simples classe de Pedido, o teste terá que usar a implementação GerenciadorTaxasJurosBD. Isto implica em fazer um busca no banco de dados, e com a performance que supomos inicialmente, isto vai nos tomar 5 segundos a cada operação. Desta forma, no método calculaTotalComTaxa(), a chamada

demora 5 segundos para retornar. Se considerarmos que na preparação da classe de testes inserimos 2 usuários de teste:

Ao configurar dois clientes fictícios (imitando o comportamento de clientes reais) e colocá-los no Banco de Dados com duas taxas distintas, a implementação Singleton nos obriga a fazer duas operações no banco de dados, perdendo outros preciosos 10 segundos, a cada teste! Ao rodar os testes, no melhor caso (rodando apenas as 3 operações descritas acima), o teste vai demorar 15 segundos para rodas. Imagine uma centena de testes como este, cada um demorando 15 segundos cada. Você vai ter que esperar um bocado...

O singleton portanto detona o desempenho de realizar testes. Você pode melhorar a situação procurando bancos de dados mais eficientes para usar, mas ainda assim sua implementação estará acoplada e limitada a uma implementação dependente de acesso a banco de dados, o que costuma ser ineficiente.

Nenhum comentário:

Postar um comentário