sexta-feira, 27 de novembro de 2009

Guicifique seus Testes - Parte 4

Este artigo é quarta 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

Colocando o Guice em Ação

A última coisa que ainda falta fazer é fazer o setup do Guice na aplicação que ele irá rodar. Todas as peças estão no lugar agora, mas o Guice ainda não está sendo invocado em lugar algum.

Aqui está uma grande regra trazida por Zorzella e Sasha, da Google, e que é boa para se ter sempre em mente: Guice is the new "new" - em outras palavras, Guice é o nova forma de se usar o operador "new".

Numa aplicação Guice, não veremos mais tantas chamadas de construtores (new()). Ao criar um objeto usando new, não tem como envolver o Guice no processo de resolver as dependências para este objeto. Para fazer proveito do poder de autowiring, é necessário usar o Guice para criar os objetos. Vamos dar uma olhada no setup da classe de testes:

Note que pedimos ao Guice para nos retornar um gerenciadorTaxas baseado apenas na interface TaxRateManager?. Nosso código de testes, portanto, não possui mais nenhuma dependência direta a uma implementação concreta, as dependências são todas encapsuladas nas regras de binding dentro da classe ModuloTestarTaxaJuros?.

Mas espera lá, na classe ModuloTestarTaxaJuros? não definimos nenhum binding para a classe Pedido, então como é que o Guice sabe o que fazer na chamada abaixo?

O Guice possui uma regra especial para difinição de classes concretas. Como Pedido é uma classe (e não uma interface), o Guice consegue adivinhar que precisamos que ele crie um objeto desta classe para nós. Porém ele vai além, ele injeta no objeto as dependências explicitadas em seu construtor marcado com a anotação @Inject.

Agora podemos enfim chegar ao teste propriamente dito, que sofre uma ligeira alteração. Lembre que tiramos do construtor da classe Pedido o parâmetro Cliente e o colocamos em um setter. Portanto, precisamos agora fornecero cliente através deste método e não mais através do construtor:

Resultados

Depois de todo este trabalho, analisemos os resultados. Executando o teste original, simulando 5 segundos de latência para cada operação realizada no banco de dados, o JUnit mostra a seguinte saída:

Ao usar o Guice para injetar a implementação fake baseada em um HashMap?, obtemos um resultado bem mais razoável:

É uma melhoria de duas ordens de grandeza! Tudo bem, este é um exemplo inventado, mas a experiência real me diz que ele não é tão desconectado da realidade. eliminar dependências com operações de I/O, bancos de dados, serviços remotos, e assim por diante, causa uma melhoria dramática na velocidade dos testes unitários.

Isto significa que é possível rodar mais testes em menos tempo, e que estamos testando uma coisa de cada vez, sem se distrair com coisas que não têm relação direta e relevante com o teste propriamente dito (ao testar a lógica de cálculo de taxas, não há razão nenhuma de precisarmos obter informações necessariamente de um banco de dados). Ao invés disso, podemos simplesmente simular o comportamento destes componentes de baixo nível.

Nenhum comentário:

Postar um comentário