TDD e Design Patterns

Uma das críticas mais importantes ao uso de Design Patterns (Padrões de Projeto) é o exagero. Muitas gente se revolta com o exagero de colocar padrões em todo o lugar do código. Isso é conhecido como sobre-engenharia.

Por outro lado, umas das práticas que mais vem criando adeptos é a construção de testes para o código. Seja seguindo uma disciplica específica como TDD ou algo mais casual, o ponto é que o código tem que ser testado.

O argumento que quero apresentar é que se utilizar padrões de projeto corretamente a construção dos testes é simplificada e vice-versa; para poder criar bons testes as classes têm que seguir bons padrões de projeto.

Essa simbiose é tão mais importante quanto mais “de integração” forem seus testes.

Imaginemos que queremos testar uma classe de processo. Este processo faz uma pesquisa no repositório, trata os dados criando algumas instâncias de objetos que ele persiste nesse mesmo repositório. Para que possamos fazer o teste temos que garantir que o processo encontra instâncias pré-determinadas, as processa e gera outras instâncias cujo estado é também pré-determinado. Digamos que o processo irá ler as instâncias A, B e C e produzir D. Para testar o sucesso do teste temos que ser capazes de ler D.

Poderiamos utilizar um repositório que conecta com o banco e ler D do banco. Contudo, estaremos também testando a integração com o banco. Além disso, precisaremos para começar de um banco de dados. Como existe uma comunicação (provavelmente em rede) o teste é demorado. O ideal seria fazer tudo sem necessitar de um banco de dados.

Se o repositório foi construído seguindo o padrão Repository podemos utilizar estratégias diferentes para o processo de teste construindo pesquisas em memória em vez de em banco. Isso é simples se utilizarmos o padrão DAO junto com QueryObject. Basta-nos criar um DAO que manipula listas em memória e não teremos mais que utilizar o banco de dados. Esse DAO pode ainda prover formas de testar a presença de objetos de forma a facilitar os testes.

Um outro exemplo simples é quando um certo processo depende de uma hora ou data. Você não vai esperar que a data chegue para testar o código , nem vai alterar a data da sua máquina. A solução é utilizar um Façade/Strategy na forma de uma interface Clock. Essa interface retorna a hora e data atual. Com isso você pode fazer o teste implementando um Clock em que você passa uma hora e data e ele sempre retorna essa (StoppedClock). No sistema real, você usa um Clock que lê a data e hora do sistema ( SystemClock). Nada se usar “new Date()”. Pode-se ainda criar um relógio que avança o tempo mais depressa que o normal (SpeedyClock) de forma a testar mudanças de estado que acontecem com a passagem de tempo.

Quanto mais corretamente for a engenharia (o design) do seu projeto, mais facilmente você encontra pontos de substituição para poder controlar os testes de maneira fácil, usando objetos que emulam o comportamento esperado ou permitem controlá-lo de forma mais simples.

Um sistema sem padrões de projeto não resiste a tentativas de teste porque é complexo desanexar as partes para que sejam testadas independentemente. O efeito disso é abandonar o teste, quando na realidade o efeito deveria ser introduzir os padrões necessários.

Adicionar Padrões de Projeto no seu sistema é um exagero? Não quando você precisa deles para testar o código.

Anúncios

Deixe uma Resposta

Please log in using one of these methods to post your comment:

Logótipo da WordPress.com

Está a comentar usando a sua conta WordPress.com Terminar Sessão /  Alterar )

Google+ photo

Está a comentar usando a sua conta Google+ Terminar Sessão /  Alterar )

Imagem do Twitter

Está a comentar usando a sua conta Twitter Terminar Sessão /  Alterar )

Facebook photo

Está a comentar usando a sua conta Facebook Terminar Sessão /  Alterar )

w

Connecting to %s