quarta-feira, 27 de abril de 2011

Testes Unitários

Olá pessoal, Apesar do tempo longe ainda estou vivo. Pois bem, as últimas semanas tem sido muito corridas, em especial por dois fatos: Testes e GUI.
Bom, em relação a GUI vou deixar para outro post. Hoje quero falar sobre testes unitários.

Há um tempo ouvi falar de um tal de teste unitário. Um negócio meio estranho de escrever um código para testar seu próprio código. Uma parada meio louca mas que todo mundo diz que é bom e funciona =). Talvez essa seja a sensação que a maioria dos programadores tem quando lê sobre testes unitários a primeira vez.
Hoje muito se fala em teste unitário, mas acredito que infelizmente muita gente ainda não faz. No projeto em que eu estava anteriormente, era bem complicada a adoção de testes unitários, não tínhamos um modelo bem definido, não tínhamos separação lógica de camadas, a GUI tinha praticamente toda a inteligência do negócio, a persistência também estava na GUI, sem contar na ferramenta defasada, enfim, um clássico projeto legado que precisa ser mantido e evoluído ao mesmo tempo. Por este cenário, era quase utópico pensar em testes unitários, em cobertura de testes então, era quase impossível.
Pois bem, neste novo projeto, produto novo, sendo concebido do zero, seguindo uma série de boas práticas, guiados pelo DDD, não tínhamos porque não fazer testes unitários. Primeiramente pensamos logo no TDD, mas como não tínhamos muita experiência com testes unitários, resolvemos adotar o teste unitário, mesmo que depois do código pronto, para depois, dentro de alguns sprints, adotarmos o TDD.
Começamos o projeto, escrevendo nossos testes baseado em alguns artigos que encontramos. Procurei alguns livros mas não encontrei nenhum aqui no Brasil que me despertasse interesse. Tinham alguns em sites lá de fora mas o prazo de entrega era muito longo, e não poderíamos esperar para começar a escrever, decidimos então fazer com o pouco conhecimento que tínhamos, as dúvidas pesquisaríamos e iríamos vencendo os obstáculos a medida que fossem aparecendo, além de refatorar os mesmos quando necessários.
Iniciamos os sprints, escrevendo nossos testes com o NUnit, adquirimos o NCover para nos auxilliar na cobertura, para identificar o que não estava coberto por testes unitários, bom, mas isso não vem ao caso pois cobertura de testes vai ser assunto para outro post.
Durantes nossos testes, não tivemos poucas dificuldades, tivemos MUITAS. A prática traz a excelência e como não tínhamos prática, estávamos muito distante da tal excelência(como ainda estamos).
Vou compartilhar agora alguns questionamentos que passamos:
· “O que testar ?“ - Apesar de ser um questionamento simples, tivemos esta dúvida. Testamos a persistência, o facade e o repositório ? Não parece redundante ? Mas pode haver alguma falha de comunicação entre as camadas, se não testarmos não pegaremos estes erros ? Devemos testar os Get e Set do modelo ? e por aí vai...

“Como testar a persistência ?” - Se temos uma camada única de persistência, usando NHibernate, não seria redundante escrever os testes de update, delete, getById, getList etc... para cada modelo ? Não teríamos apenas que testar estes métodos uma vez ? Não teríamos apenas que testar os mapeamentos dos modelos ? Não teríamos como fazer isso de forma automática ? Além disso, temos que garantir que o banco de dados seja o mesmo ao final do teste, para não impactar testes futuros, como gerar estes dados ? Como garantir a estabilidade do ambiente ? e por aí vai....

· “Usar ou não usar Mocks” – Quando devemos usar Mocks ? Para que eles servem ? Usando Mocks não estamos fazendo com que o ambiente de teste seja “forjado”, fugindo da realidade ? e por aí vai...

· “Que padrões adotar para testes” – Uma classe de teste para cada classe de negocio ? Quais padrões de nomenclaturas ? Como separar os namespaces e assemblies de testes ? e por aí vai...

Nós sabíamos que não seria fácil, o começo é a parte mais traumática de qualquer novo desafio, e não contentes com estas dúvidas, fomos atrás de respostas. Durante nossas pesquisas, vimos inúmeros exemplo simples, como por exemplo, testando os Get e Set, testando o somar, subtrair, testando uma rotina de desconto, validação de dados, enfim... De certa forma nos decepcionamos, a sensação que tivemos é de que testes unitários, cobertura de testes era uma lenda. Todo mundo dizia que era bom, todo mundo dizia que era importante, mas ninguém dizia como fazer de fato em um projeto real.
Pois bem, não desistimos, sabíamos da importância dos testes, sabíamos que só dependia de nós. Estudamos mais um pouco, erramos mais um pouco, refatoramos muito e continuamos a escrever nossos testes.
Na falta de padrões de mercado que nos dessem segurança, seguimos de acordo com o que achávamos ser o mais correto e coerente baseado em tudo o que havíamos lido, feito e discutido. Decidimos que todas as classes seriam testadas, criamos um método genérico para testar o mapeamento de todas as classes no NHibernate, separamos os testes em dois assemblies, um de testes de interface e outro para os testes do Selenium, para a nomenclatura usaríamos em português de forma mais clara possível, mesmo que as vezes o nome fique gigante rs.
Bom, seguimos escrevendo nossos testes, buscando o máximo de cobertura possível. Ainda existem alguns desafios como por exemplo a automatização dos teste de GUI, estamos amadurecendo no uso do Selenium e em breve postarei sobre isso.
Bom, não sei se consegui transmitir aqui a mensagem desejada. O que eu queria deixar claro é que fazer testes unitários NÃO é tão fácil quanto parece. Existe uma grande possibilidade de você desanimar e chutar o balde diante das dificuldades iniciais, e continuar desenvolvendo sem testes unitários, a sensação que você pode ter no inicio é de que isso é uma lenda e não funciona.
Mas eu lhes digo, é apenas uma sensação inicial, testes unitários funcionam e eu não consigo me imaginar desenvolvendo sem eles. Em breve postarei aqui sobre os benefícios que percebi após adoção dos testes unitários.
Meu recado final é: Façam testes unitários. Superem as dificuldades. No início eles não serão os testes mais elegantes e eficientes do mundo, mas com o tempo você pega o jeito, refatora os mesmos e logo logo não conseguirá mais programar sem eles, portanto, se for para desenvolver um projeto de software, faça testes unitários, sempre que possível.

P.S.:É claro que estes testes devem estar em um ambiente automatizado, com cobertura medida e tudo mais, mas isso é assunto para um outro post, neste limito-me a algumas das experiência vividas com Testes Unitários, sem nem mesmo entrar no mérito do TDD ainda. Caso alguém tenha um livro para indicar sobre testes unitários, padrões e boas práticas de testes unitários, TDD para nos indicar, fiquem a vontade =) =). Fiquem a vontade também para compartilhar suas experiências, vamos mostrar para o mundo que SIM, teste unitário funciona e é fundamental para o desenvolvimento de softwares de qualidade.

Até logo pessoal, um grande abraço.

Nenhum comentário:

Postar um comentário