quinta-feira, 24 de setembro de 2009

Introdução ao TDD

A algum tempo comecei a adotar a prática de TDD (Test-Driven Development). No início pensava "não tem como desenvolver desse jeito", em pouco tempo passei a pensar "não tem como desenvolver sem isso".

Existe muita informação na Internet a respeito de TDD, por isso não quero falar de como fazer, mas sim, dos conceitos e práticas importantes para quem está começando agora. Para quem está começando, parece que TDD é relacionado apenas a "testes automatizados", mas é muito mais que isso.

Definição de TDD

A prática de TDD se resume a três passos simples, mas fundamentais:
  • Escrever um teste que falhe - o primeiro passo é pensar o que deseja-se fazer. Com isso, criar um teste definindo o contexto, a execução e as expectativas;
  • Fazer o teste passar - deve-se escrever o mínimo de código necessário para fazer o teste passar, nada além disso;
  • Refatorar - deve-se rever o código e verificar se há melhorias a serem feitas. Essas melhorias não podem alterar o comportamento apenas a estrutura do código.
Apesar dos passos serem simples, no início é difícil segui-los. Nossa tendência é escrever imediatamente todo o código e no final adicionar os testes. É justamente esse o ponto mais crítico e mais importante na adoção de TDD, se acostumar a escrever o teste primeiro. Toda a vantagem do desenvolvimento dirigido por testes vêm disso.

Podemos utilizar as três regras definidas por Robert Martin:
  • Você não pode escrever nenhum código a não ser que ele seja necessário para fazer um teste que esteja falhando passar;
  • Você não pode escrever nenhum teste além do necessário para falhar. E, falhas de compilação também são falhas;
  • Você não pode escrever nenhum código além do necessário para fazer o teste passar;
Em resumo, só escrever qualquer código necessário para atender um teste que esteja falhando, nada além disso.

Benefícios

A grande pergunta é: quais os benefícios de TDD?

Para quem ainda não conhece a prática, a única vantagem vista são os testes unitários. Ninguém vê logo de cara os demais benefícios que essa prática traz. Alguns deles que posso destacar:
  • Requisitos melhor detalhados - os testes ajudam a entender melhor os requisitos;
  • Codificar apenas o necessário - como apenas é codificado o mínimo necessário para passar um teste evitamos introduzir códigos que não temos certeza se serão utilizados;
  • Reduz o acoplamento das classes - para que os testes sejam fáceis de serem criados, as classes não podem ter um forte acoplamento;
  • Deixa claro o comportamento do sistema - para um desenvolvedor que entra no projeto, ou quando vamos alterar um código existente, sempre podemos consultar os testes para saber qual o comportamento esperado;
  • Incentiva a refatoração - é bastante comum ouvirmos a frase "é melhor não mexer ali pois não sabemos quais os problemas que pode gerar". Com um sistema com boa cobertura de testes, o desenvolvedor tem muito mais confiança para fazer qualquer alteração;
  • Menor utilização do depurador - com os testes é muito mais fácil verificar o comportamento. Evitamos ter que abrir o sistema, acessar meia dúzia de telas e só depois testar a funcionalidade;
Um fato interessante da prática de TDD é que ele mostra claramente os pontos do sistema onde o design está ruim. Basicamente, se está difícil ou trabalhoso testar determinada parte do sistema, isso é um grande sinal de um problema no design.

O que testar?

O ideal é que 100% do sistema esteja coberto por testes, porém isso dificilmente é possível. Há determinados pontos do sistema onde não é possível criar testes unitários ou o trabalho não compensa.

Normalmente o código que acessa recursos externos (banco de dados, sistema de arquivos, etc) não pode ser testado com testes unitários. Para estes casos é necessário criar testes integrados que, normalmente são mais difíceis de serem criados/mantidos e mais lentos. Deve-se tentar desacoplar ao máximo o sistema destes recursos externos.

Vale a pena?

No início é difícil se acostumar a essa nova forma de trabalho, porém em pouco tempo percebemos os benefícios e não queremos voltar atrás. No momento que percebi que estava gastando muito menos tempo depurando os programas e o código estava melhor, vi que esse era um caminho sem volta.