Como consegui começar a praticar TDD

Marcio Frayze
19 min readFeb 17, 2020

Neste artigo parto do pressuposto que você já leu o básico sobre desenvolvimento de software guiado por testes. Aqui, descrevo alguns dos problemas que enfrentei ao tentar internalizar esta prática no meu dia a dia e como consegui transpô-los.

Primeiros contatos

Conheci o TDD quando cursava ciência da computação, por volta de 2003. Estava estudando sobre Programação Extrema e adorei as ideias, mas tinha muita dificuldade de colocar algumas em prática, entre elas, o desenvolvimento de software guiado por testes (TDD). Foram muitos anos até internaliza-la, mas hoje não consigo entender como era capaz de desenvolver softwares sem esta prática!

O objetivo deste artigo é tentar ajudar pessoas que tem interesse em TDD, mas que ainda não conseguiram incluir esta prática no seu dia a dia. Abaixo detalho os problemas que enfrentei e dou algumas dicas de como superei cada um deles.

Estude conceitos antes de bibliotecas e frameworks

Quando decidi aplicar TDD, meu time já utilizava o jUnit para testes automatizados, mas os testes eram feitos após a implementação do código de produção. Como já conhecia as ferramentas e tinha noção dos conceitos básicos por trás do TDD, foi natural tentar partir direto para prática sem antes estudar mais a fundo a teoria. E o resultado não poderia ser outro: frustração. Mudar a forma de trabalho que pratiquei durante mais de 10 anos foi muito difícil e desisti diversas vezes no meio do caminho. Lia artigos na internet e a teoria parecia interessante, mas não conseguia entender como praticar.

Em algum momento percebi que precisava me dedicar mais aos conceitos e dois livros me ajudaram muito a esclarecer diversas dúvidas. São eles:

Então se você está decidida a praticar TDD, sugiro que comece lendo estes livros. O primeiro é bastante curto, objetivo e explica muito bem os fundamentos. O segundo é mais extenso, aprofunda bem vários temas e me ajudou a finalmente entender como praticar TDD.

Desenvolver software guiado por testes parece ser muito fácil, podendo ser resumido em apenas três passos simples:

  • Escreva um teste automatizado que falhe ao ser executado;
  • Escreva o código de produção suficiente para que este teste passe;
  • Refatore o código e repita o ciclo.
Ciclo do TDD: Escreva um teste, Faça o teste passar, Refatore e reinicie o ciclo.
Clico básico do TDD

Como esta teoria parece ser simples, é tentador negligenciar o estudo dos conceitos e partir direto para prática. Não cometa este erro. Estude mais a fundo os princípios e fundamentos e tudo ficará muito mais fácil. Aprenda com aqueles pessoas que já exploraram muito mais o tema e abriram caminho para você.

Minha recomendação é que leia pelo menos o primeiro livro que citei acima. Você vai gastar apenas algumas horas e o aprendizado vai te poupar muitos e muitos dias de frustrações. E assim que tiver um pouco mais de tempo, leia também o segundo livro que citei. É difícil descrever o quanto aprendi com ele! Definitivamente mudou completamente a forma como desenvolvo software.

Escreva os testes antes SEMPRE

No começo, antes de estudar melhor sobre o assunto, tive muita dificuldade para entender a importância de obedecer a ordem do ciclo do TDD. Era comum codificar a lógica de negócio para em seguida sofrer ao tentar escrever os testes. Sabia que não estava praticando TDD, mas achava que o resultado final seria o mesmo, afinal, estava escrevendo os testes automatizados, apenas não seguida a ordem estabelecida pelo TDD. Demorei para entender que não estava deixando os testes guiarem o design do meu código e o quanto eu estava perdendo ao fazer isso.

E quando ia tentar escrever os testes, parecia que estava brigando com meu código e tinha a sensação de estar escrevendo um software pior. Fazia coisas que sabia que eram erradas, mas pareciam ser a única opção! Um exemplo recorrente: como testar um determinado trecho de código de forma isolada, se era um método privado? Será que devo mudar o método que quero testar de private para protect ou public? E acabei fazendo isso (erroneamente) algumas vezes. Sempre me sentia culpado e percebia que havia algo errado, mas acabava colocando a culpa no teste. Achava que cometer aqueles desvios arquiteturais era a única forma de conseguir tornar aquele código testável.

Mas conforme desenvolvia o software desta maneira, a cobertura de testes caía e a qualidade do software caía junto com ela. E como a arquitetura do sistema ficava cada vez menos testável, virava uma bola de neve até chegar ao ponto de ficar muito difícil criar novos testes. No final aquilo se tornava uma experiência muito frustrante e via muito pouco benefício em trabalhar desta forma, já que os ganhos não estavam compensando o custo.

Só fui entender melhor isso quando li o livro TDD Desenvolvimento Guiado por Testes e passei então a obedecer o fluxo correto do TDD. Mas resistir o impulso de escrever “só mais essa linha de código” antes de existir um teste ainda é mais difícil do que parece. Praticar TDD exige disciplina. Tenha um pouco de paciência e resista a tentação de adiantar o código de produção. Mesmo que você tenha certeza de como ficará o código daqui alguns minutos, pare de implementar o código de produção assim que o teste ficar verde. Passe para etapa de refatoração (remoção de código duplicado) e depois volte para a criação de um novo teste. Crie um teste que falhe e só então passe para próxima etapa de construção do produto. Você ficará surpresa com a quantidade de vezes que o teste vai guiar sua arquitetura para uma direção diferente da que tinha inicialmente imaginado.

Depois de algum tempo você irá internalizar este fluxo, mas nas primeiras vezes precisará ficar muito atenta. Isso costuma ser mais fácil quando estamos trabalhando com programação pareada ou mob programming, já que outras pessoas vão ajudar a nos lembrar de não cometer este erro tão comum.

Não atire no mensageiro

Se começar a ficar muito difícil criar um novo teste, talvez você tenha subestimado a etapa de refatoração e seja um bom momento para analisar a arquitetura do seu sistema. Não fique irritada com o teste! Pelo contrário, fique feliz de ter encontrado um ponto que precisa de atenção e que, se não fosse o teste, talvez aparecessem problemas muito maiores no futuro. Quanto antes encontrarmos e corrigirmos as falhas de design, mais fácil e barato será reparar estes problemas. E a prática de TDD é uma excelente forma de fazer isso.

Não use ferramentas de testes muito avançadas

É bastante comum encontrar iniciantes em TDD tentando utilizar ferramentas avançadas para criação de objetos dubles complexos, com uso de reflections e até chegando a tentar criar dublês de métodos estáticos ou métodos privados. Não faça isso! Essas ferramentas podem ser úteis em alguns casos muito raros, mas em 99,999% das situações o problema está na arquitetura do sistema e, corrigindo essas falhas, deixamos de precisar de técnicas tão invasivas. Quanto melhor a arquitetura, mais fácil é criar testes automatizados da aplicação.

Estude arquitetura de software e código limpo

Como disse logo acima, a arquitetura do sistema tem uma importância muito significativa na criação de sistemas testáveis. Portando, estude sobre boas práticas de programação. Aprenda como implementar códigos limpos, entenda os princípios do SOLID e como criar uma boa arquitetura de software e aplique tudo isso em seus códigos. Abaixo listo algumas fontes que me ajudaram muito nesta trajetória:

  • Clean Code (Código Limpo) — Um clássico escrito pelo Robert Cecil Martin. Nele você vai entender os fundamentos de como escrever um código que será mais fácil de manter e refatorar.
  • Clean Archictecture (Arquitetura Limpa) — Do mesmo autor do Código Limpo. Ele vai te ajudar a entender melhor o que é e como criar uma boa arquitetura de software. Gravei um podcast onde falo sobre este livro.
  • Refactoring — Escrito por Martin Fowler, outro clássico do desenvolvimento de software. Uma das principais etapas do TDD é a parte de refatorar o código e este livro é a referencia natural para entender como fazer isso da melhor maneira possível.
  • Building Evolutionary Architectures — Cheguei a gravar um podcast sobre este livro. Esta obra vai te ajudar a entender como montar uma arquitetura evolucionária. Você pode também assistir esta palestra da Rebecca Parsons, CTO da ThoughtWorks e uma das autoras do livro.

Siga os princípios de yagni e último momento responsável

Outra dica é sempre seguir o princípio do you ain’t gonna need it (você não vai precisar disso), conhecido pela abreviação yagni. E também o last responsible moment (último momento responsável).

Seguindo estas duas ideias, junto com TDD, conseguimos adiar as tomadas de decisões até o último instante seguro. Assim, conseguimos juntar o máximo de informações possível para que, quando realmente precisarmos tomar uma decisão, ela seja feita da forma mais informada possível.

“Há coisas que não sabemos que não sabemos.” — Neal Ford

Mesmo que você tenha certeza que um determinado modelo de banco de dados será a melhor solução, que determinada tecnologia é a mais adequada para o problema e que certa arquitetura seria a mais indicada, resista a tentação de tomar esta decisão até que chegue o último momento responsável.

Pode ser que existam vários fatores que você ainda desconhece e que podem mudar toda tomada de decisões. Talvez no começo do projeto um banco de dados NoSQL pareça ser a melhor alternativa, até que aparece um impedimento no meio do caminho que faz com que este modelo de banco deixe de ser uma boa solução. Caso seu time tenha tomado a decisão de usar NoSQL de forma prematura, o custo e a dor de mudar para outra solução será muito maior do que se você tivesse simplesmente esperado até o último momento responsável.

Você encontra mais informações sobre o conceitos de último momento responsável e arquitetura evolucionária neste artigo do Neal Ford e Rebecca Parsons (em inglês).

Execute os testes automaticamente ao salvar qualquer arquivo

A técnica que mais me ajudou no começo e continua ajudando é configurar a ferramenta de build para que execute todos os testes de forma automática sempre que salvo um arquivo. Deixo então uma janela em meu monitor secundário que fica executando os testes a todo instante, enquanto mantenho no monitor primário a IDE ou editor. Quando estou trabalhando com apenas um monitor, deixo um terminal aberto na parte inferior da tela rodando os testes. Desta maneira, tenho duas grandes vantagens:

  • Não esqueço de executar os testes com frequência;
  • Quando uma alteração causa algum efeito colateral indesejado que quebre algum teste, fico sabendo no mesmo instante.

Caso esteja programando em Java, o gradle possui um parâmetro que faz isso para você. Caso esteja utilizando alguma outra ferramenta de build, procure na documentação e deve encontrar algo relacionado com o termo watch. Quando estou programando em Elm, utilizo o elm-test em conjunto com o parâmetro watch, por exemplo. Em alguns casos a ferramenta entr pode ajudar nesta tarefa.

Recomendo fortemente que comece desta forma. Claro que em sistemas com muitos testes você precisará adaptar este modelo, já que a execução de todos os testes pode ser muito demorada e exigir muito recurso (memória e processador).

Até hoje continuo usando esta técnica e não conseguiria contar a quantidade de vezes que isso ajudou a identificar problemas de forma antecipada e economizou muito tempo.

Não basta automatizar a execução dos testes

Algumas pessoas desenvolvedoras dizem estar implementando testes de unidade pelo simples fato de estarem utilizando alguma biblioteca (como por exemplo JUnit ou NUnit) para facilitar a execução tarefas. Mas na prática, o que estão fazendo é apenas facilitar a execução de uma rotina qualquer, como se fosse uma função main. Isso não pode ser chamado de teste automatizado, e muito menos de teste de unidade.

Já aconteceu algumas vezes de atuar em projetos que tinham uma suposta alta cobertura de testes onde o time inclusive utilizava ferramentas de analise como o SonarQube, mas logo no começo apareceriam algumas coisas estranhas como testes que não possuíam nenhum assert! Ou seja, a única forma do teste falhar era se ocorresse uma exceção durante sua execução, caso contrário, sempre terminava com sucesso. Outro erro comum eram os testes imprimirem coisas no console (em geral, o resultado da execução). Resumindo: eram ótimos exemplos de como não fazer testes automatizados.

Os asserts são parte fundamental dos testes. É neste momento que validamos o resultado de sua execução. Quando não é feito da forma adequada, corremos o risco de criarmos falsos positivos, falsos negativos ou ainda testes muito frágeis. Por isso, não tenha pressa ao escrever os asserts. Não podem ser genéricos demais mas também não podem ser muito frágeis.

E nunca imprima nada no console. É função dos asserts indicar se o teste executou com sucesso ou não e, em caso de falhas, o próprio framework de testes irá se encarregar de mostrar onde ocorreu o problema. Por isso, outro ponto muito importante é dar um nome significativo para o teste. Eu uso e recomendo o padrão Given-When-Then.

Priorize testes de unidade

Pirâmide de testes

Podemos separar os testes automatizados em três categorias: ponta a ponta, integrados e de unidade. Idealmente um time que pratique TDD deve criar estes 3 tipos de testes. A dúvida mais comum é questionar se não basta criar os testes ponta a ponta para testar tudo de uma única vez. Mas cada tipo de teste tem um objetivo diferente e recomendo que comece com os de unidade.

Não vou entrar muito a fundo neste tema, mas gostaria de registrar aqui um alerta: não priorize testes ponta a ponta. Perdi a conta de quantas vezes vi times que focavam apenas nos testes ponta a ponta e depois de alguns meses, quando a suíte começava a ficar muito grande (e com testes muito frágeis e lentos), abandonavam os testes. Se você tiver nesta situação, recomendo ler este artigo (em inglês) escrito por Ham Vocke. Lá ele explica muito bem esta questão.

O teste deve guiar o desenvolvimento

Quando conheci a expressão “desenvolvimento de software guiado por testes”, acabei dando muita ênfase na ideia de que estaria testando meu software de forma automatizada e pouca atenção na parte de guiar o desenvolvimento.

E desenvolvimento de software guiado por testes (TDD) é, como o nome já diz, sobre desenvolvimento de software. Não esqueça disso e deixe que os testes te guiem. Mesmo que as vezes pareça que você está indo para um caminho oposto ao que o seu instinto está te dizendo, dê uma chance aos testes e veja para onde ele está tentando te levar. Não é incomum que vá parar em um caminho muito mais curto, simples e claro do que o que você estava originalmente pensando.

Não desista no primeiro obstáculo

TDD é uma prática e toda prática exige treino, comprometimento e uma dose de perseverança. Assim como aprender um novo instrumento musical ou andar de bicicleta, é necessário estudo e dedicação. Às vezes eu caio da bicicleta ou erro o tempo da batida da bateria no ensaio com a banda. E nas primeiras vezes que tentei aplicar TDD tive muita dificuldade para encontrar o melhor nome para os testes, não sabia como implementar os asserts e demorava para encontrar quão pequeno o escopo do teste deveria ser, entre outras muitas dificuldades.

Gostaria de dizer que eventualmente encontrei a melhor maneira de fazer tudo isso, mas a verdade é que, assim como aprender a tocar um instrumento, minha prática de TDD torna-se cada vez melhor conforme treino, e a cada dia encontro alguma forma melhor de aplicá-la. Por isso continuo experimentando, errando e tentando novamente. E claro, estudando! Não basta apenas praticar. O progresso é muito mais rápido quando aprendemos com pessoas que já estão praticando a muito mais tempo que a gente.

Chegue perto de 100% de cobertura

A quantidade adequada de cobertura de testes é polêmica. O único consenso é que não existe um valor mágico, mas justamente por ser algo que depende do bom senso do time, vejo com frequência pessoas usando isso como desculpa para diminuir a cobertura. E a consequência é que a arquitetura sofre, o que faz com que fique cada vez mais difícil escrever novos testes e a cobertura diminui cada vez mais.

Então minha sugestão é, no começo, pecar pelo excesso. Siga o TDD mais a risca e só escreva um código novo se ele estiver coberto por algum teste escrito previamente (seja teste de unidade, integrado ou ponta a ponta). Provavelmente a parte mais difícil de conseguir atingir uma alta cobertura são as camadas relacionada a infraestrutura (como métodos responsáveis pelo acesso ao banco de dados, por exemplo). É possível (e recomendável) criar testes para estas partes do código, mas podem exigir um conhecimento um pouco mais aprofundado para criar estes testes automatizados.

Isso ocorre pois para que seja possível implementa-los, a arquitetura do seu sistema precisa ter um nível de maturidade razoável. Se seu time souber como aplicar os princípios do SOLID (em especial, o princípio da inversão de dependência), este testes já passam a ser muito mais fáceis de implementar. Se estiver tendo muita dificuldade em aumentar a cobertura de código de determinadas camadas do seu sistema, tente no começo pelo menos garantir que as regras de negócio estão totalmente cobertas.

Existem ferramentas que geram relatórios de cobertura de testes, inclusive integradas com as IDEs. Estes relatórios exibem quais linhas foram testadas e quais não foram, porcentagem de cobertura de cada classe e pacote do seu sistema, entre outras informações que podem te ajudar a identificar pontos que precisam de mais atenção. Só tome cuidado para não se prender demais aos relatórios! Use com moderação e de forma responsável. Nunca use como uma métrica gerencial. O Brian Marick escreveu este artigo (em inglês) onde explica em detalhes os cuidados necessários para se utilizar as métricas de uma forma saudável.

Definição de código legado

Existem várias formas de definir o que é um código legado. Antes de conhecer TDD, interpretava como sendo sinônimo de código antigo, ultrapassado. Que tinham sido desenvolvidos com tecnologias que não eram mais utilizadas em sistemas novos. Mas Feather tem uma definição um pouco diferente desta:

Para mim, o código legado é simplesmente código sem testes. (…) Código sem testes é código ruim. Não importa o quão bem escrito é; não importa o quão bonita ou orientada a objetos ou bem encapsulada é. Com os testes, podemos mudar o comportamento do nosso código de forma rápida e verificável. Sem eles, realmente não sabemos se nosso código está ficando melhor ou pior. — Trabalho Eficaz com Código Legado, Michael Feathers.

Conhecer esta definição me causou um impacto imediato. O código que havia escrito cinco minutos antes de ler esta definição não tinha testes. Eu havia acabado de implementar um código legado! E, pelo menos para mim, esta definição faz bastante sentido. E é muito fácil de classificar se o código que está na minha frente é legado ou não, bastando responder a pergunta: possui testes automatizados?

Para o seu bem, para a saúde mental de seus colegas e para o bem do produto, pare de escrever código legado.

Não tenha medo de reverter o código quando estiver com dificuldades

Antigamente passava boa parte do tempo tentando entender os motivos de por quê meu código não estar funcionando. Escrevia várias linhas de código, executava e o resultado não era o que eu esperava. Então alterava um pouco, executava, … e este ciclo vicioso se repetia. Era comum passar muito tempo (horas ou em casos extremos até mesmo dias) em uma situação onde o software estava em um estado inconsistente, sem se comportar como era o esperado. Eram muitas marretadas até conseguir molda-lo para algo próximo ao que eu queria.

O TDD veio para mudar completamente esta minha rotina. Aplicando desenvolvimento guiado por testes, integração contínua e outras práticas da programação extrema, quando sinto que estou tendo muita dificuldade em compilar o projeto ou implementar o código para fazer um teste passar, minha reação é descartar todas alterações e voltar para o estado anterior (quando todos os testes passavam) para então escrever um teste com um escopo menor e continuar o fluxo.

Ter muita dificuldade para resolver o problema que está enfrentando é um sinal que o teste que escreveu está muito amplo e você está dando um passo maior que a perna. Nesta situação, o melhor é dar um passo para trás. Volte para o estado onde todos os testes estavam passando (descartando todas suas alterações) e escreva um teste com um escopo mais limitado e então siga mais um vez o ciclo do TDD. Se ainda sentir que não está conseguindo evoluir, volte mais uma vez e tente dar um passo ainda menor, até conseguir avançar de forma segura (com os testes passando). Aí sim refatore seu código e escreva o próximo teste para dar mais um passo em direção ao seu objetivo.

O momento em que decidi seguir TDD

Como disse, conheci esta prática quando ainda estava na faculdade, mas foi só depois de mais de uma década de formado que comecei a pratica-la.

Estava em um projeto onde tive a oportunidade de desenvolver uma parte bem isolada. Era quase como se fosse um projeto novo, já que não dependia de quase nada do resto da base de código. Resolvi que iria deixar os testes guiarem o desenvolvimento desta parte.

Tive algumas poucas dificuldades e tudo ia tranquilo, até chegar a hora que precisei utilizar um objeto dublê um pouco mais complicado. Neste momento eu já havia lido os dois livros que indiquei mais acima (TDD Desenvolvimento Guiado por Testes e o Desenvolvimento de Software Orientado a Objetos, Guiado Por Testes). Conseguia entender a teoria, mas demorei um pouco para chegar a conclusão que o que eu precisava naquela situação era um spy.

O sistema tinha algumas integrações problemáticas e decidimos criar um decorator que seria usado no entorno dessas chamadas para monitora-las. Caso um determinado padrão fosse encontrado, um alerta seria emitido. Era basicamente uma solução caseira e simples para monitorar as integrações.

Em uma primeira versão, a “emissão” seria apenas imprimir algumas informações na log do sistema. A tentação em não testar a linha de código que emitiria o alerta foi grande, confesso! Mas havia me comprometido a deixar os testes me guiarem… e os testes estavam me dizendo que simplesmente colocar um “System.out.println” no meio do código não era uma boa ideia. Contra minha própria vontade, resolvi seguir os testes. Criei uma interface para especificar a entidade que iria emitir o alerta e para os testes criei um spy a partir desta interface. Assim, utilizando a ideia de inversão de dependência, diminui o acoplamento do meu código. Agora a regra de negócio não estaria mais acoplada com a implementação concreta de emissão de alertas e ela não precisaria mais saber como o alerta seria emitido, já que estaria acoplada apenas com uma interface. Mas claro que antes disso tudo, criei um teste de unidade que me ajudou a achar esta solução.

Um efeito colateral positivo desta abordagem foi que no futuro, quando ao invés de simplesmente imprimir no console decidíssemos utilizar um mecanismo mais complexo (como postar em uma fila de mensageria, por exemplo), precisaria apenas injetar outra implementação concreta desta interface e não seria necessário mudar nenhuma linha do meu código de negócio.

Até este instante estava tudo bem e faltava pouco para implantarmos esta funcionalidade em produção. Mas alguns dias depois precisei alterar a lógica de quando o alerta seria emitido. Segui o ritual do TDD: alterei o teste referente aquela funcionalidade (que passou a falhar), corrigi a implementação (fazendo com que o teste ficasse verde) e em seguida refatorei o código.

Mas de repente um dos testes passou a falhar. Eu tinha certeza que minhas alterações não haviam introduzido nenhum erro no código. Mas a certeza era tamanha que minha primeira reação foi pensar que o teste estivesse errado. Abri a classe do teste e olhei seu histórico. Nenhuma alteração recente. Abri novamente o código que estava refatorando e fiz um rollback para uma versão anterior e o teste passou. Neste instante admiti para mim mesmo que havia cometido algum erro durante a refatoração. Fiz um diff entre o código novo e o versionado e bingo! Eu havia removido uma linha sem querer. Sem aquela linha, o código continuava compilando e executando normalmente, mas nunca iria emitir nenhum alerta!

Eu nunca iria detectar este problema no ambiente de desenvolvimento ou homologação e talvez nem mesmo em produção. Como era algo que deveria ser esporádico, talvez não estranhasse tanto a sua ausência. E isso iria esconder um monte de problemas que estavam ocorrendo em produção e que só detectei graças e este alerta. Neste instante percebi a quantidade de tempo e dor de cabeça que aquele teste que havia hesitado em fazer havia me poupado. E senti na pele as vantagens de seguir o desenvolvimento guiado por testes.

Não é normal ter medo

Está com medo de publicar algo em produção? Ou alterar uma parte do sistema? Em algumas empresas este medo já faz parte da rotina. Mas isso não pode ser considerado normal. É um sintoma de algum problema e precisa ser tratado. Nunca ignore o seu medo ou de qualquer membro do seu time.

Não tem certeza se a sua alteração vai funcionar ou tem receios que ela possa impactar alguma outra funcionalidade pré existente? A forma mais eficaz de resolver isso é através do desenvolvimento guiado por testes.

“Testes são a Pedra Filosofal do programador, transmutando medo em tédio”. — TDD Desenvolvimento Guiado por Testes, Kent Beck.

Em projetos que não tem nenhum tipo de automação ou testes, pode parecer muito difícil chegar neste estágio. E em alguns sistemas maiores, pode ser complicado mesmo. Mas dando um passo de cada vez, um dia seu time chega lá. Se este for seu cenário atual, o livro Trabalho Eficaz com Código Legado (Working Effectively with Legacy Code) do Michael Feathers talvez possa te ajudar a encontrar um bom caminho para melhorar o código do seu sistema.

Menos debug, mais testes automatizados

Ao começar a desenvolver meus softwares guiado por testes, passei a notar que a quantidade de vezes que utilizo o debug através da IDE diminuiu drasticamente. Ao invés de perder tempo tentando montar uma massa de testes para executar a aplicação manualmente, encontrar o melhor ponto para adicionar um ponto de parada e acompanhar atentamente a execução de cada passo da aplicação, passou a ser muito mais fácil e natural criar um cenário de testes automatizados. Seja através de testes de unidade, teste integrado ou ponta a ponta, a grande maioria das vezes consigo montar um teste que reproduz o cenário que preciso analisar.

Utilizar o debug é uma tarefa que (pelo menos pra mim) é bastante estressante. Para simular o erro uma única vez, precisava montar a massa de dados executando scripts no banco ou até mesmo alterar a massa de sistema que faço integração para conseguir montar o cenário. Feito isso, se o ponto de parada (break point) estivesse no lugar errado ou pressionasse a tecla equivalente a step over quando deveria ter feito um step in, estragava a massa e tinha que começar tudo de novo.

Além de ser uma tarefa que consome muito tempo, é bastante delicada, o que gera o estresse. Quem nunca soltou uma palavrão quando depois de muito trabalho a IDE passa pela linha do break point quando esperávamos que ela parasse?!

Outra vantagem de usar testes automatizados ao invés de debug é que além de ser muito mais fácil de executar múltiplas vezes, irá garantir que a falha que está sendo corrigida não irá ocorrer outra vez no futuro, servindo como um teste de regressão.

Conclusão

Praticar TDD é mais difícil do que dizem, mas também mais recompensador do que parece. Algumas pessoas não se adaptam a esta forma de trabalho (como o famoso caso do DHH ) e talvez você e seu time também cheguem a conclusão que este modelo não é o ideal para vocês. Mas só tem uma forma de descobrir: praticando e dando uma chance real para o TDD. E para que este experimento seja adequado é necessário estudo, treino e dedicação. Mas prometo que, mesmo que no final você chegue a conclusão que TDD não é para você, com certeza vai aprender muita coisa útil neste processo, independente do modelo que decida seguir depois.

Obrigado por ler até aqui! Se gostou deste texto, tenho mais alguns publicados em minha página pessoal e também sou coautor do p de Podcast, um podcast sobre boas práticas de programação.

--

--