Exemplo TDD, parte 1: Por onde começar
Publicado por Ivan Sanchez em Quinta-Feira, Novembro 9, 2006
Aviso! Todo o contexto deste exemplo é 100% fictício.
Qualquer um pode colaborar com sugestões/críticas/perguntas, então participe!
Começamos há pouco tempo um novo projeto de um sistema para controlar o acesso e acompanhar a frequencia dos estudantes de um cursinho pré-vestibular. A integração com a catraca ainda não é prioridade, então a nossa primeira tarefa é: armazenar e contabilizar as horas dos estudantes.
Nossa intenção é desenvolver orientado a testes, então surge a pergunta: por onde começar?
Como já sabemos, o primeiro passo para criação de código usando TDD é criar um teste que falhe. Embora o primeiro teste pareça sempre o mais complicado para se escrever, depois de algum treino ele acaba se tornando tão simples quanto os demais. Isso porque não há mesmo muita diferença entre eles.
Então como escrever o primeiro teste? A resposta é: não importa, desde que ele seja escrito. Não há necessidade de se preocupar se o teste está errado, uma vez que o código da aplicação sequer existe. Se ele parecer errado basta reescrevê-lo, e isso poderá ser feito em qualquer momento, mesmo depois de existirem centenas de testes.
Um teste é a descrição de um comportamento do sistema. Então basta termos uma idéia qualquer do que o sistema tem que fazer que já podemos começar.
Resolvemos começar escrevendo uma classe para representar as horas dos estudantes. Começamos com um item qualquer na nossa checklist mental:
- Representar uma hora qualquer no formato hh:mm
Então vamos fazer o nosso primeiro teste para criar um objeto da classe Hora com um determinado valor e verificar se este foi armazendo. O código fica assim:
package dojo.exemplo.tdd;
import junit.framework.TestCase;
public class HoraTest extends TestCase
{
public void testCriacaoHoraQuinzeHoras()
{
Hora hora = new Hora("15:00");
assertEquals("15:00", hora.toString());
}
}
Estamos especificando um comportamento esperado da nossa classe e fazemos uma validação, o que significa que nosso primeiro teste está pronto. Porém este ainda não compila porque não temos a classe Hora e seu construtor. Então chegou a hora de criá-la:
package dojo.exemplo.tdd;
public class Hora
{
public Hora(String string)
{
}
}
Isso é o mínimo que precisamos para rodar o primeiro teste. E com isso temos o nosso primeiro erro:
junit.framework.ComparisonFailure: expected: but was:
Nossa tarefa agora é fazer o teste passar, e a maneira mais simples para isso é criar o método toString() na classe Hora, retornando uma constante:
public String toString()
{
return "15:00";
}
Com esta alteração o teste agora passa. Porém sentimos que ainda podemos melhorar, e para isso só temos duas alternativas válidas: fazer um refactoring ou escrever um novo teste.
Decidimos fazer um novo teste na classe HoraTest para quebrar esta primeira implementação:
public void testCriacaoHoraDezEMeia()
{
Hora hora = new Hora("10:30");
assertEquals("10:30", hora.toString());
}
Isto já é o suficiente para fazer o teste falhar, o que já esperávamos uma vez que nossa classe não permite criar uma hora diferente de 15:00. Portanto precisamos modificá-la:
private String hora;
public Hora(String string)
{
this.hora = string;
}
public String toString()
{
return this.hora;
}
Rodamos os nossos dois testes e agora ambos passam. E agora já é possível pensar em pelo menos mais duas classes que a classe tem que fazer:
Representar uma hora qualquer no formato hh:mm- Permitir a criação de uma hora padrão (“00:00″)
- Não permitir que se crie hora fora do formato hh:mm
(Começaremos a próxima parte do nosso exemplo resolvendo estes dois itens)
Roberto disse
Ivan, apenas uma sugestão, creio que seria interessante já utilizar o Junit 4.0 que dá suporte a anotações, facilitando o uso para casos que o retorno esperado são exceções.
No guj vc pediu algumas sugestões e citou alguns tópicos e acho que para manter a simplicidade (um dos tópicos) é interessante não aplicar patterns, já que é algo muito atômico (pelo menos nos testes unitários).
Parabéns pela iniciativa
Vinícius Manhães Teles disse
Ivan,
Antes de mais nada, parabéns!
Tem um tutorial de TDD que escrevi há algum tempo onde você também poderia coletar algumas idéias. Está no endereço: http://www.improveit.com.br/xp/praticas/tdd .
Espero que seja útil.
Leandro Zis disse
Ivan, parabens pela inicitiva.
Ricardo, eu discordo de você quando diz que patterns aumentam a complexidade, eu acho justamente o contrario. E não entendi oq vc quis dizer com “atômico”.
Ivan Sanchez disse
Roberto,
Primeiramente, obrigado pelo feedback
Então, eu cheguei até a pensar em colocar os testes em pseudo-código, já que meu objetivo era mostrar TDD, independente da ferramenta. Acabei fazendo no jUnit 1.3.8 para facilitar os usuários do Java 1.4 (a maioria que eu conheço). Mas concordo que o jUnit 4 tem suas facilidades, e espero que eu consiga mostrá-las em breve
Quanto aos design patterns, não entendi o que você quis dizer com “atômico” neste caso. O que isso seria? A minha sugestão era para mostrar que é possível aplicar design patterns programando com TDD (principalmente buscando remover duplicações), coisa que muita gente duvida já que a modelagem é feita incrementalmente.
Ivan Sanchez disse
Vinicius,
Conheço o seu tutorial e ele com certeza foi bastante útil. Inclusive conduzi uma sessão de programação num treinamento onde reproduzíamos o seu exemplo para o pessoal treinar TDD, com resultados bem legais.
Agora a minha idéia é partir de um exemplo mais simples ainda para coletar as principais dúvidas de quem está aprendendo TDD e tentar respondê-las a cada nova parte do exemplo que eu for publicando. Tomara que dê certo
E obrigado pelos parabéns!
Ivan Sanchez disse
Leandro,
Também concordo que patterns diminuem a complexidade. Porém quando mal encaixados ou usado em excesso, eles podem acabar deixando o código mais complexo. Por isso costumo aplicá-los principalmente durante refactorings, e não durante a solução dos testes.
Espero que eu consiga deixar estas idéias claras nas próximas partes do exemplo. Até lá obrigado pela ajuda
Ps.: O nome do cara do comentário acima é Roberto, e não Ricardo
Exemplo TDD, parte 2: Baby Steps e Tratamento de Exceções « Coding Dojo Floripa disse
[...] Terminamos a primeira parte do nosso exemplo com os seguintes itens para implementar: [...]