Test-Driven Development
O ciclo Red-Green-Refactor
Seção intitulada “O ciclo Red-Green-Refactor”graph LR
RED["RED<br/>escreve teste que falha"] --> GREEN["GREEN<br/>código mínimo que passa"]
GREEN --> REFACTOR["REFACTOR<br/>melhora o desenho, verde mantido"]
REFACTOR --> RED
- Red — escreva um teste pequeno para um comportamento que ainda não existe. Ele deve falhar (e por compilar-e-falhar, não por erro de compilação bobo). O teste vermelho define a especificação do próximo passo.
- Green — escreva o mínimo de código de produção para passar. É permitido — e recomendado — “fingir” (retornar uma constante) para chegar ao verde rápido. O objetivo aqui é a barra verde, não a elegância.
- Refactor — com a rede verde protegendo, melhore o desenho: elimine duplicação, renomeie, extraia. Sem adicionar comportamento e sem sair do verde. É o elo direto com refactoring e Técnicas de Refactoring.
A cadência é rápida: dezenas de ciclos por hora. A regra de Beck é sempre manter a barra verde a poucos segundos de distância.
TDD como técnica de DESIGN
Seção intitulada “TDD como técnica de DESIGN”O ganho mais profundo do TDD não é a suíte que sobra, e sim o desenho que emerge. Escrever o teste primeiro obriga você a usar a API antes de implementá-la, do ponto de vista do cliente. Isso tem consequências arquiteturais diretas:
- Baixo acoplamento — para testar uma unidade isolada, suas dependências precisam ser injetáveis; o design é empurrado para composição em vez de instanciação interna.
- Aderência a DIP — as colaborações viram interfaces (portas) que o teste substitui por dublês, materializando o DIP - Dependency Inversion Principle. O código passa a depender de abstrações.
- Interfaces enxutas — se a API é dolorosa de usar no teste, ela é dolorosa de usar em produção. A dor aparece cedo e barata.
- Responsabilidades separadas — uma classe que exige dez mocks para ser testada está gritando violação de SRP. TDD torna o cheiro imediato.
Em suma: testabilidade e bom design são a mesma propriedade vista de dois ângulos (Testabilidade e Arquitetura). Os princípios SOLID deixam de ser teoria e viram consequência prática de fechar ciclos vermelho-verde-refatorar.
Baby steps
Seção intitulada “Baby steps”O tamanho do passo é ajustável, e essa é uma habilidade central. Quando o problema é claro, passos maiores. Quando você está incerto ou o teste anterior ficou vermelho de forma surpreendente, encurte o passo: implemente por triangulação (dois ou três exemplos que forçam a generalização) em vez de saltar direto para o algoritmo geral. Passos pequenos reduzem o tempo de depuração — se algo quebra, a causa está nas últimas poucas linhas.
Um kata simples por TDD: FizzBuzz
Seção intitulada “Um kata simples por TDD: FizzBuzz”Regra: números viram texto; múltiplos de 3 viram “Fizz”; de 5, “Buzz”; de ambos, “FizzBuzz”.
Ciclo 1 — Red. O caso mais simples:
class FizzBuzzTest {
FizzBuzz fizzBuzz = new FizzBuzz();
@Test void numeroComumViraSuaString() { assertThat(fizzBuzz.converter(1)).isEqualTo("1"); }}Green — o mínimo que passa (fingir é legítimo):
public class FizzBuzz { public String converter(int n) { return "1"; }}Ciclo 2 — Red (triangulação força a generalizar):
@Testvoid outroNumeroComumViraSuaString() { assertThat(fizzBuzz.converter(2)).isEqualTo("2");}Green — a constante não sobrevive; generaliza:
public String converter(int n) { return String.valueOf(n);}Ciclos 3 e 4 — Red para Fizz e Buzz, resolvidos com if. Ciclo 5 — Red para FizzBuzz. Estado final, já com o Refactor aplicado (ordem dos casos e concatenação limpa):
public class FizzBuzz {
public String converter(int n) { String resultado = ""; if (n % 3 == 0) resultado += "Fizz"; if (n % 5 == 0) resultado += "Buzz"; return resultado.isEmpty() ? String.valueOf(n) : resultado; }}Teste final consolidado com @ParameterizedTest, expressando a especificação inteira:
class FizzBuzzTest {
FizzBuzz fizzBuzz = new FizzBuzz();
@ParameterizedTest @CsvSource({ "1, 1", "2, 2", "3, Fizz", "5, Buzz", "15, FizzBuzz", "30, FizzBuzz" }) void converteConformeRegra(int entrada, String esperado) { assertThat(fizzBuzz.converter(entrada)).isEqualTo(esperado); }}Repare que o algoritmo não foi “projetado no papel”: emergiu dos casos, um por vez.
Classicist vs Mockist (Detroit vs London school)
Seção intitulada “Classicist vs Mockist (Detroit vs London school)”Há duas escolas sobre como isolar a unidade sob TDD, sistematizadas por Martin Fowler em Mocks Aren’t Stubs:
| Classicist / Detroit | Mockist / London | |
|---|---|---|
| Isolamento | Só mocka o que é caro/externo (banco, rede); usa objetos reais como colaboradores | Mocka todas as dependências da classe sob teste |
| Foco da verificação | Estado — o resultado final observável | Comportamento — as interações/chamadas entre objetos |
| Direção do design | Middle-out: desenvolve o domínio e deixa o desenho emergir | Outside-in: começa pela borda e descobre colaboradores como interfaces |
| Risco | Testes de unidade maiores, fronteira menos nítida | Acoplamento a detalhes de interação; testes frágeis a refatoração |
Não é religião. A escola mockista casa naturalmente com outside-in TDD e ajuda a descobrir portas (interfaces) na fronteira do domínio. A classicista produz testes mais resistentes a refactoring, porque verifica resultado e não mecânica. Na prática, a maioria dos times mistura: estilo classicista no domínio, dublês nas fronteiras de infraestrutura. A taxonomia dos dublês usados por cada estilo está em Test Doubles - Stub, Spy, Mock e Fake.
Quando NÃO aplicar (ou aplicar com parcimônia)
Seção intitulada “Quando NÃO aplicar (ou aplicar com parcimônia)”- Espaço de solução desconhecido / spike: quando você ainda não sabe o que construir, um spike exploratório sem testes esclarece o problema; depois joga fora o spike e refaz por TDD.
- Código de UI muito visual ou glue trivial: o custo do teste pode superar o retorno; teste o comportamento por baixo.
- Requisitos ainda voláteis a cada minuto: escrever testes que serão jogados fora no dia seguinte é desperdício — estabilize a direção primeiro.
TDD não é obrigatório em todo lugar, mas a dificuldade de aplicá-lo geralmente denuncia um problema de design, não um defeito do TDD.
Anti-padrões e erros comuns
Seção intitulada “Anti-padrões e erros comuns”- Escrever o teste depois e chamar de TDD: perde o efeito de design; vira só verificação retroativa.
- Pular o Refactor: sem o terceiro passo, o código acumula a dívida dos atalhos do Green; a suíte protege exatamente para permitir a limpeza.
- Passos grandes demais: teste que cobre muito de uma vez torna a depuração cara quando fica vermelho.
- Testar detalhes de implementação (mockismo excessivo): testes frágeis que quebram a cada refatoração legítima.
- Green sem Red antes: se você não viu o teste falhar, não sabe se ele testa algo.
- Refatorar com barra vermelha: nunca; refatore só no verde.
Relações
Seção intitulada “Relações”- Testes e TDD
- Fundamentos da Automação de Testes
- Princípio FIRST
- Test Doubles - Stub, Spy, Mock e Fake
- Tipos de Teste - Unit, Integration e E2E
- Técnicas de Refactoring · Clean Code e Refactoring
- SOLID · DIP - Dependency Inversion Principle · SRP - Single Responsibility Principle
- Testabilidade e Arquitetura
Perguntas de revisão
Seção intitulada “Perguntas de revisão”1. Por que é essencial ver o teste falhar (Red) antes de escrever o código?
Resposta
Porque um teste que nunca foi visto falhando pode estar verde por engano (sem assert efetivo, ou testando a coisa errada). O Red confirma que o teste realmente exercita o comportamento ausente e que o Green subsequente foi mesmo o código que o satisfez.
2. Em que sentido TDD é uma técnica de design e não só de verificação?
Resposta
Escrever o teste primeiro obriga a usar a API pela ótica do cliente e a injetar dependências para isolar a unidade. Isso empurra o código para baixo acoplamento, interfaces enxutas e aderência a DIP/SRP. O desenho emerge da necessidade de tornar cada passo testável.
3. Qual a diferença central entre a escola classicista e a mockista?
Resposta
A classicista (Detroit) verifica estado e só mocka dependências caras/externas, usando objetos reais como colaboradores. A mockista (London) mocka todas as dependências e verifica comportamento (interações). A mockista favorece outside-in e descoberta de portas; a classicista gera testes mais resistentes a refactoring.
4. Por que pular o passo Refactor compromete o TDD?
Resposta
Porque o Green é obtido com o código mínimo, muitas vezes deselegante ou duplicado. O Refactor existe para pagar essa dívida enquanto a rede verde protege o comportamento. Sem ele, os atalhos acumulam e o design degrada, anulando o benefício de desenho do ciclo.