TDD não é fazer testes unitários

Separados Parece mas não é

TDD e testes unitários são conceitos inter-relacionados, porém com escopos e objetivos diferentes. Fazer testes unitários, mesmo antes do código, não significa usar Test Driven Development. Essa distinção é importante visto que os principais benefícios de usar TDD estão relacionados à entender como essa técnica funciona e aplicá-la corretamente. Nesse artigo eu procuro esclarecer essa diferença e mostrar como equipes que já fazem testes unitários podem se beneficiar do uso do TDD.

O que é TDD?

TDD

TDD é um processo de desenvolvimento descrito por Kent Beck em seu livro Test Driven Development By Example. Nesse processo um código novo é sempre escrito a partir de um teste falhando, ou seja, escrevemos o teste antes de escrever o código. Basicamente ao desenvolver com TDD a seguinte sequência irá guiar a criação do novo código:

1- Red: Escrever um teste falhando;
2- Green: Fazer o teste passar, mesmo que seja escrevendo um código longe do ideal;
3- Refactor: Melhorar a implementação de acordo com boas práticas de programação, como por exemplo eliminar duplicação.

Nas entrelinhas desses três passos existem alguns conceitos importantes que diferenciam essa prática do ato de simplesmente escrever testes unitários.

Conceitos importantes sobre TDD

TDD está mais relacionado com design do que com testes

A principal motivação em escrever o teste antes do código está nas raízes do TDD, que é mais uma ferramenta de design do que de teste [1]. Ao escrever o teste antes pensamos na classe do ponto de vista de quem vai chamá-la, favorecendo o desenvolvimento de uma classe mais simples de ser usada.

Outro ponto importante é que ao fazermos o teste antes buscamos validar o comportamento da classe de maneira fácil. Isso estimula a criação de classes menores e mais coesas. Quanto maior e mais responsabilidades a classe tiver mais difícil será validar seu comportamento externamente [2].

Assim o teste se torna um termômetro do design, ou seja, se o teste começa a ficar muito grande ou difícil de escrever é sinal que a implementação que pensamos originalmente está complicada demais.

TDD sempre começa com um teste falhando

Filosofo

O processo de TDD começa com um dos pontos mais polêmicos do ciclo, fazendo o teste falhar. Considerando que é óbvio que o teste vai falhar, por quê executá-lo mesmo assim? A resposta está em uma pergunta filosófica: Quem testa o teste?
Ao fazer o teste falhar estamos validando se o teste está escrito corretamente, ou seja, se caso o código estiver errado o teste irá falhar. Quando essa etapa não é executada a confiança no teste é afetada e o desenvolvedor ocasionalmente muda o código da aplicação para verificar se o teste realmente está fazendo o que deveria.

Outro desdobramento interessante de sempre começar com um teste falhando é que isso força justificar cada linha de código. Como consequência teremos apenas o código necessário e nada mais, afastando um erro comum em desenvolvimento de software: over-engineering.

Ao trabalhar com código existente, eventualmente um teste que esperava-se falhar, não falha, porque o código existente já faz o que desejamos, eliminando um outro problema, trabalho desnecessário.

Em TDD nem todos os testes são unitários

Apesar da maioria dos testes criados com TDD serem unitários, dependendo do tipo de classe sendo desenvolvida, é oportuno criar testes de integração (ex. DAOs e Gateways em geral).

Sinais de alerta

Existem alguns padrões que podem ser um indicativo de que TDD não está sendo aplicado corretamente ou nem mesmo sendo feito:

  • Fazer vários testes antes de começar a implementação;
  • Escrever com frequência testes que tenham apenas o objetivo de validar o comportamente atual, sem que isso resulte em novo código ou alteração do existente;
  • Testes com loops (for, while, etc.);
  • Testes com condicionais (if,switch, etc.);
  • Testes com muitos assert (a maioria dos testes resultantes de TDD contém poucos asserts).

Complementos

A melhor fonte para aprender a teoria e a prática dessa técnica é o livro, já citado, do próprio Kent Beck, Test Driven Development By Example. Em Lidando com testes mentirosos - Show me the code eu mostro um exemplo de projeto feito com TDD.


[1] Test Driven Development By Example, pág. 204
[2] Ver também: God Object