TDD: o ciclo Red-Green-Refactor

Resumo em uma linha

TDD é um ciclo de três passos — escreva um teste que falha (Red), faça-o passar com o mínimo de código (Green), melhore o design com a rede de segurança verde (Refactor) — repetido em ciclos de minutos. Pra sair do Red rumo ao Green, Kent Beck descreve três estratégias: Obvious Implementation (escreve o código real quando é óbvio), Fake It (retorna uma constante e generaliza depois) e Triangulação (um segundo teste força a generalização certa). O efeito mais profundo não é a suíte de testes que sobra — é que o teste, escrito antes da implementação, vira o primeiro cliente da sua API, moldando o design antes que ele exista.

Imagine um escalador subindo uma parede de rocha. Ele não sobe trinta metros e só então pensa em proteção. A cada lance, ele prende a corda num ponto fixo, testa o peso, e só depois avança. Se cair, cai um metro — não trinta.

TDD é escalar assim. Você não escreve trezentas linhas no escuro pra depois rezar pra que funcionem. Você prende uma proteção (um teste que falha), sobe um lance (o código mínimo pra passar), arruma o equipamento na cintura (refatora), e repete. Cada ciclo dura minutos. Se errar, o erro é pequeno e o teste te avisa na hora.

A sigla é Red-Green-Refactor — vermelho, verde, refatorar. É o coração da disciplina que Kent Beck formalizou no fim dos anos 1990, dentro do Extreme Programming. Esta nota é sobre a mecânica do ciclo. Quando vale a pena aplicar, quando não vale, e o pragmatismo do dia a dia ficam em [[09 - TDD na prática]].

Os três passos

O ciclo tem exatamente três estados. Você nunca está em dois ao mesmo tempo.

1. Red — escreva um teste que falha

Você começa pelo teste, não pelo código de produção. O teste descreve o comportamento que você quer que exista. Você roda a suíte. O teste falha — vermelho. Tem que falhar. A feature ainda não existe.

Parece contraintuitivo escrever um teste pra algo que não existe. Mas é justamente aí que está o truque: o teste te força a responder, antes de escrever uma linha de produção, como esse código vai ser usado. Que método chamo? Que parâmetros passo? O que recebo de volta?

2. Green — faça passar com o mínimo de código

Agora você escreve o mínimo de código de produção pra deixar o teste verde. Mínimo mesmo. Não é hora de elegância, abstração ou performance. É hora de feedback.

Pode ser feio. Pode ser um valor fixo retornado na cara dura (mais sobre isso adiante). O objetivo único do Green é: voltar pro verde o mais rápido possível, pra ter de novo uma base sólida sob os pés.

Resista ao over-engineering

A pressa de já “deixar bem feito” no Green é a porta de entrada do over-engineering. Você adiciona um cache que ninguém pediu, uma camada de abstração pra um caso que não existe. O Green te disciplina: faça passar, só isso. O design vem no próximo passo, sob proteção.

3. Refactor — melhore o design com tudo verde

Com o teste verde, você tem uma rede de segurança. Agora — e só agora — você melhora o design: extrai um método, renomeia uma variável, remove duplicação, separa responsabilidades.

A cada pequena mudança, você roda os testes. Se continuam verdes, o comportamento foi preservado e você pode seguir. Se um fica vermelho, você quebrou algo — desfaz e tenta de novo, em um passo menor.

É no Refactor que o design emerge. Você não desenhou a arquitetura perfeita de antemão; você deixou ela crescer, refatoração a refatoração, sempre com a corda presa.

Depois do Refactor, você volta pro Red com o próximo comportamento. E o ciclo recomeça.

stateDiagram-v2
    [*] --> Red
    Red --> Green: escreve mínimo de código
    Green --> Refactor: teste passa
    Refactor --> Red: próximo comportamento
    Refactor --> Refactor: ainda verde, segue limpando
    Red: Red — teste falha
    Green: Green — teste passa
    Refactor: Refactor — melhora design, mantém verde

Leitura do diagrama

O ciclo nunca para de fato — ele dá voltas. Saímos de Red (teste falhando) pro Green (passa com o mínimo), depois pro Refactor (limpa o design). O laço de Refactor sobre si mesmo mostra que você pode fazer várias pequenas melhorias em sequência, sempre conferindo o verde. Do Refactor, volta-se pro Red com o próximo comportamento. Cada volta completa dura minutos.

Vídeo — o ciclo em 6 minutos

“Unit Testing & TDD Explained: Red-Green-Refactor, Mocks” (programmerCave, ~6 min) percorre test doubles e o ciclo Red-Green-Refactor na mesma ordem desta nota: teste primeiro, mínimo de código pra ficar verde, refatoração só sob rede de segurança. Bom resumo em vídeo pra fixar a sequência antes de entrar nas estratégias de Green, logo abaixo.

Por que cada passo importa

Os três passos não são burocracia. Cada um resolve um problema específico de quem escreve software.

flowchart TD
    R["RED<br/>teste falha"] --> RG["Garante que o teste<br/>de fato testa algo"]
    G["GREEN<br/>passa com mínimo"] --> GG["Feedback imediato +<br/>evita over-engineering"]
    F["REFACTOR<br/>limpa com verde"] --> FG["Design emerge com<br/>rede de segurança"]
    RG --> CONF["Confiança em<br/>cada lance"]
    GG --> CONF
    FG --> CONF

Leitura do diagrama

Cada passo do ciclo (esquerda) entrega uma garantia concreta (centro), e as três garantias somadas produzem o resultado que justifica a disciplina: confiança a cada lance da escalada (direita). Red prova que o teste tem dentes. Green dá feedback rápido e freia o exagero. Refactor faz o design crescer sob proteção.

  • Red garante que o teste funciona como detector. Ver o vermelho é a calibração do alarme de incêndio: se ele nunca apitou, você não confia nele.
  • Green te dá feedback em segundos. Você sabe na hora se foi na direção certa. E, ao exigir só o mínimo, ele te impede de construir o que ainda não precisa.
  • Refactor é onde mora a qualidade do design. Sem testes, refatorar é apavorante — qualquer mexida pode quebrar algo silenciosamente. Com a suíte verde, refatorar vira uma operação segura e barata.

Note que os três passos são interdependentes, não independentes. Pular o Red enfraquece a garantia do Green — você não sabe se o teste de fato testa alguma coisa. Pular o Refactor acumula dívida que torna o próximo Red mais caro de escrever, porque o código em volta já está mais confuso. É por isso que “fazer TDD pela metade” — escrever testes só depois, ou fazer Green sem nunca refatorar — não entrega as mesmas garantias do ciclo completo; entrega uma fração dele, e a fração mais fraca é sempre a que sustentava as outras duas.

O que TDD te força a fazer

O efeito mais profundo de TDD não está nos testes que sobram. Está no que ele muda em você enquanto escreve. TDD é menos uma técnica de teste e mais uma técnica de design.

Martin Fowler

“Test-Driven Development is a technique for building software that guides software development by writing tests.” O foco está em guiar o desenvolvimento — os testes são consequência, não o objetivo.

Pensar no design antes

O teste é o primeiro cliente da sua API. Antes de implementar, você já decidiu como o código será chamado — porque você acabou de chamá-lo, no teste. Se a chamada ficou desajeitada no teste, ela vai ficar desajeitada pra todo mundo. Você descobre isso antes de escrever a implementação, não meses depois quando outro time reclama. Veja [[04 - Testes unitários]] pra entender a unidade que você está colocando na bancada.

Escrever código testável

Código difícil de testar quase sempre é código mal projetado. Se você precisa subir meio sistema pra testar uma regra, é sinal de que a regra está acoplada demais. TDD empurra você na direção de dependências injetadas, responsabilidades separadas, fronteiras claras — exatamente os princípios de [[03-Dominios/Engenharia/Design de Software/SOLID/index|SOLID]]. A dor de testar é um feedback de design chegando cedo.

Resolver o problema certo

Se você não consegue nem escrever o teste, você não entendeu o requisito. O teste te obriga a tornar o comportamento esperado concreto: dado isto, espero aquilo. Ambiguidade no requisito vira ambiguidade no teste — e aí você para e vai perguntar, em vez de codar a coisa errada com confiança.

Feedback rápido, não código no escuro

Sem TDD, é comum escrever um bloco grande e só no fim descobrir que a fundação estava errada. Com ciclos de minutos, o pior caso é perder alguns minutos. Você nunca está a mais de um passo de uma base verde.

TDD não substitui pensar

TDD não dispensa o design de cabeça. Você ainda precisa de uma direção geral. O que o ciclo faz é manter o design detalhado sempre validado por código que roda, em vez de viver só na sua imaginação.

Baby steps e “fake it till you make it”

A unidade de tempo de TDD é o passo de bebê (baby step). Cada ciclo cobre um pedacinho de comportamento. Por que tão pequeno? Porque quanto menor o passo, menor o estrago quando você erra — e mais cedo você percebe.

Kent Beck descreve três estratégias pra chegar do Red ao Green:

EstratégiaQuando usarO que você faz
Obvious ImplementationA implementação é óbvia e você confia nelaEscreve o código real direto
Fake ItNão sabe ainda como implementarRetorna uma constante; depois substitui por código real aos poucos
TriangulaçãoNão está nada seguro da abstração certaEscreve um 2º (ou 3º) teste que força a generalização

As três têm uma ordem natural de preferência. Beck a resume assim: se você sabe o que digitar, digite a Obvious Implementation. Se não sabe, Fake It. Se mesmo com o Fake It o design certo ainda não aparece, triangule. O Obvious Implementation é a “segunda marcha” — você o usa quando está confiante, e reduz a marcha pro Fake It no instante em que o cérebro começar a assinar cheques que os dedos não conseguem descontar.

Obvious Implementation — escreva o real direto

Quando o código é trivial e você confia nele, não brinque de fingir. isEmpty() numa lista? return size == 0. Pronto. Inventar um Fake It aqui só adiciona cerimônia. A armadilha é o excesso de confiança: se a “implementação óbvia” der vermelho duas vezes seguidas, é sinal pra reduzir a marcha e voltar pros passos pequenos.

Obvious Implementation e a escada de transformações

Escrever a implementação óbvia só é seguro quando ela corresponde a uma transformação baixa na escada da TPP — trocar uma constante por uma expressão simples, por exemplo. Se a “implementação óbvia” exige pular direto pra expressão → função ou statement → recursão, ela não é tão óbvia assim: é sinal pra reduzir a marcha, ir de Fake It e deixar a triangulação decidir o próximo passo.

Fake It — retorne a constante e generalize depois

O Fake It é o famoso “fake it till you make it”. Você quer testar uma soma? No primeiro teste, soma(2, 3) deve dar 5 — então retorne 5, cravado:

int soma(int a, int b) {
    return 5; // descaradamente fake
}

Verde. Absurdo? Por enquanto. Mas você já tem a corda presa, e a duplicação agora está explícita: o 5 do teste e o 5 do código são o mesmo fato dito duas vezes. O próximo passo é remover essa duplicação trocando a constante por variáveis aos poucos — return a + b — até não sobrar nada fake.

Fake It é psicológico, não preguiça

Beck é explícito no livro: Fake It não é atalho por preguiça, é um dispositivo pra manter a confiança quando a forma final ainda não está clara. O “fake” separa duas perguntas que, misturadas, travam gente iniciante — “isso compila e roda?” e “qual é a abstração certa?” — resolvendo uma de cada vez. Assim que a duplicação entre teste e código fica óbvia, ela vira o guia da próxima refatoração: eliminar a duplicação é, por construção, chegar na implementação real.

Triangulação — force a generalização com um segundo caso

A triangulação é o que te tira da farsa quando você nem confia que a forma certa é a + b. Você adiciona um segundo teste que contradiz a constante: soma(4, 7) deve dar 11. Agora o return 5 não passa mais:

// teste 1: soma(2, 3) == 5
// teste 2: soma(4, 7) == 11  -> mata o "return 5"

O segundo ponto triangula a direção certa, como dois pontos definem uma reta: você é forçado a escrever return a + b. A generalização emerge porque um segundo caso a exigiu — não porque você adivinhou.

Generalize só quando um segundo caso forçar

A regra de ouro da triangulação: não generalize por antecipação. Espere o segundo exemplo te obrigar. Isso te protege de abstrações erradas inventadas cedo demais — você só constrói a abstração que os fatos pediram.

A lista de testes

Antes de começar o primeiro ciclo, Beck rabisca uma lista de testes (test list): num canto da tela ou num papel, ele anota todos os casos que vêm à cabeça pro comportamento que vai construir. “Soma de positivos. Soma com zero. Soma com negativo. Overflow.” A lista não é um plano rígido — é o backlog do ciclo.

A condução é simples e disciplinada: você pega um item da lista, faz o ciclo Red-Green-Refactor pra ele, risca o item — e, no caminho, quase sempre descobre casos novos que não tinha previsto. Você os anota na lista na hora, sem desviar do item atual. Quando a lista esvazia, a feature acabou.

A lista é memória de trabalho, não contrato

A lista de testes resolve um problema cognitivo: ela tira de dentro da sua cabeça os casos que você ainda não cobriu, liberando atenção pro ciclo presente. Você adiciona, descarta e reordena conforme aprende. Itens que pareciam necessários somem; outros nascem do meio do código. É um documento vivo de minutos, não um requisito formal.

O diagrama abaixo mostra a lista de testes como o motor do ciclo: ela alimenta cada Red, e o próprio ciclo realimenta a lista com casos descobertos no caminho.

flowchart LR
    LIST["Lista de testes<br/>(backlog vivo)"] -->|"pega 1 item"| RED["Red<br/>teste falha"]
    RED -->|"Fake It / Obvious / Triangulação"| GREEN["Green<br/>passa com mínimo"]
    GREEN -->|"sob rede verde"| REF["Refactor<br/>limpa design"]
    REF -->|"risca o item"| LIST
    REF -.->|"descobriu caso novo"| LIST
    LIST -->|"lista vazia"| DONE["Feature pronta"]

Leitura do diagrama

A lista de testes (esquerda) é a fonte de cada ciclo: você pega um item e entra no Red. O Green usa uma das três estratégias pra passar; o Refactor limpa sob a rede verde. Ao terminar, você risca o item — e a seta tracejada de volta à lista mostra o efeito colateral fértil: o ciclo quase sempre revela casos novos que você anota na hora. Quando a lista esvazia, a feature está pronta.

flowchart TD
    START["Teste no vermelho"] --> Q1{"Sei como<br/>implementar?"}
    Q1 -->|"Sim, é óbvio"| OBV["Obvious Implementation<br/>escreve o real"]
    Q1 -->|"Não"| Q2{"A abstração<br/>está clara?"}
    Q2 -->|"Mais ou menos"| FAKE["Fake It<br/>retorna constante"]
    Q2 -->|"Nada clara"| TRI["Triangulação<br/>2º teste força generalizar"]
    OBV --> GREEN["Verde"]
    FAKE --> GREEN
    TRI --> GREEN
    GREEN --> REF["Refactor"]

Leitura do diagrama

Diante de um teste vermelho, a escolha da estratégia depende de duas perguntas. Se a implementação é óbvia, escreva o código real direto. Se não, e a abstração ainda está vaga, “finja” com uma constante (Fake It). Se está muito vaga, force a forma certa com um segundo teste (triangulação). Todos os caminhos levam ao verde e seguem pro Refactor.

A ordem das transformações (Transformation Priority Premise)

Obvious, Fake It e Triangulação escolhem a estratégia geral pra sair do Red. Robert C. Martin (Uncle Bob) levou a mesma pergunta um nível mais fundo, pra dentro do código: dado que você vai mudar a implementação pra fazer o teste passar, qual transformação concreta aplicar primeiro? Na Transformation Priority Premise (2013), ele lista transformações da mais simples pra mais complexa:

  1. {} → nil — nenhum código → código que usa nil
  2. nil → constante — nil vira um valor constante
  3. constante → constante+ — uma constante simples vira outra mais elaborada
  4. constante → escalar — a constante vira variável ou parâmetro
  5. statement → statements — adiciona instruções incondicionais
  6. incondicional → if — separa caminhos de execução com uma condicional
  7. escalar → array — a variável vira um array
  8. array → container — o array vira uma estrutura de dados mais rica
  9. statement → recursão — código linear vira uma abordagem recursiva
  10. if → while — a condicional vira um laço
  11. expressão → função — a expressão vira uma função/algoritmo
  12. variável → atribuição — passa a reatribuir valores a uma variável

A regra prática: diante de um teste vermelho, prefira sempre a transformação mais alta dessa lista que já resolve o teste. Martin ilustra o custo de não seguir a ordem com o kata do Word Wrap: ao escolher cedo demais uma transformação de alta complexidade (expressão → função), ele criou um impasse — no terceiro teste, nenhuma transformação pequena resolvia mais, e só reescrever o algoritmo inteiro fazia o teste passar. Escolhendo transformações de baixo pra cima — tratando primeiro palavras longas com incondicional → if e statement → recursão, antes de qualquer algoritmo elaborado — a solução emergiu incrementalmente, sem impasses.

flowchart BT
    T1["1 · {} → nil"] --> T2["2 · nil → constante"]
    T2 --> T3["3 · constante → constante+"]
    T3 --> T4["4 · constante → escalar"]
    T4 --> T5["5 · statement → statements"]
    T5 --> T6["6 · incondicional → if"]
    T6 --> T7["7 · escalar → array"]
    T7 --> T8["8 · array → container"]
    T8 --> T9["9 · statement → recursão"]
    T9 --> T10["10 · if → while"]
    T10 --> T11["11 · expressão → função"]
    T11 --> T12["12 · variável → atribuição"]
    style T1 fill:#c8e6c9
    style T12 fill:#ffcdd2

Leitura do diagrama

A escada sobe do mais simples (verde, base) ao mais complexo (vermelho, topo). Diante de um teste vermelho, você tenta primeiro a transformação mais baixa que ainda resolve — só sobe a escada quando o degrau atual não é suficiente. É essa disciplina de “não pular degraus” que evita o impasse do Word Wrap.

Um exemplo rápido de progressão

Considere testar uma função valorAbsoluto(n). Primeiro teste: valorAbsoluto(0) == 0. A menor transformação que resolve é {} → nil seguida de nil → constante: return 0. Verde.

Segundo teste: valorAbsoluto(5) == 5. return 0 falha. A menor transformação que resolve agora é constante → escalar: return n. Verde — e repare que ainda não precisamos de nenhuma condicional.

Terceiro teste: valorAbsoluto(-5) == 5. return n falha, porque devolve -5. Aqui a menor transformação que resolve é incondicional → if: if (n < 0) return -n; return n;. Verde de novo — sem pular direto pra uma função elaborada com bibliotecas matemáticas ou bit tricks, que resolveria o mesmo teste mas custaria mais e esconderia a intenção.

Em nenhum ponto pulamos pra uma transformação alta (recursão, função elaborada) quando uma baixa já bastava. Essa é exatamente a disciplina que evita o impasse: cada teste te empurra só um degrau acima do necessário, nunca dois.

A mesma lógica da triangulação, um nível mais fundo

Prefira sempre o passo mais simples que ainda faz o teste passar, e deixe a generalização emergir do próximo teste — não da sua intuição sobre “a forma certa”. É a triangulação aplicada à própria operação de código, não só à API.

Escolhendo o próximo item da lista com a TPP

A lista de testes diz o quê testar a seguir; a Transformation Priority Premise diz quanto você vai precisar mexer no código pra fazer esse próximo teste passar. As duas se completam. Ao escolher o próximo item da lista, prefira o caso que força a transformação mais baixa ainda disponível — não necessariamente o mais “importante” do ponto de vista de negócio. Beck não ataca o caso mais complexo primeiro só porque parece mais valioso; ele ataca o caso que o deixa no próximo degrau da escada, não dois degraus acima. É esse casamento entre lista e escada de transformações que mantém os passos de bebê realmente pequenos, ciclo após ciclo.

A cadência: ciclos de minutos

O erro de quem está aprendendo é imaginar que cada ciclo é uma sessão de trabalho. Não é. Um ciclo Red-Green-Refactor saudável dura minutos — às vezes menos de um. Se um ciclo seu está levando meia hora, ou o passo era grande demais, ou você ficou preso no Green sem reduzir a marcha.

Esse ritmo tem dois efeitos psicológicos que importam mais do que parecem. O primeiro: o verde frequente é dopamina. Cada barra verde é uma microvitória, e elas se acumulam num fluxo que sustenta a concentração por horas. O segundo: cada verde é um checkpoint — um ponto de salvamento de jogo. Se a próxima tentativa der errado, você não perde o jogo inteiro; volta pro último save, que está a um ou dois minutos atrás.

Commit no verde

A regra prática que fecha o ciclo: faça commit sempre que estiver verde (e nunca no vermelho). Cada verde é um estado consistente do sistema — testes passando, comportamento preservado. Commits pequenos e frequentes no verde te dão um histórico de pontos seguros pra onde voltar. Se um experimento de design der errado no meio de um Refactor, git reset te leva ao último verde sem dó.

TCR — o commit-no-verde levado ao extremo

Anos depois do livro, Kent Beck experimentou um fluxo radical chamado TCRtest && commit || revert. A ideia: você roda um único comando que executa os testes; se passam, commita automático; se falham, reverte automático pro último verde. O castigo de quebrar a barra não é debugar — é perder o que você acabou de escrever. Isso te força a passos minúsculos, porque ninguém quer reescrever vinte minutos de código. É a versão mais agressiva do commit-no-verde e um bom experimento mental pra calibrar o tamanho dos seus passos, mesmo que você não o adote no dia a dia.

Um ciclo de ponta a ponta

Pra ver as peças se encaixando, acompanhe uma fatia minúscula: um Carrinho que soma o total dos itens. Comece pela lista de testes: “carrinho vazio dá total zero”, “um item dá o preço do item”, “dois itens somam os preços”.

Pega o primeiro item. Red: assertEquals(0, carrinho.total()) — não compila, depois falha. Green com Obvious Implementation, porque é trivial: return 0. Verde em segundos. Refactor: nada a limpar ainda. Commit. Risca o item.

Segundo item: “um item dá o preço”. Red: adiciono um item de 10 e espero 10; o return 0 falha. Aqui não confio na forma final, então Fake It: return 10. Verde — mas a duplicação entre o teste e o código grita. Terceiro item força a saída da farsa: dois itens de 10 e 5 devem dar 15, e o return 10 morre. Isso me triangula pro código real: somar os preços dos itens. Verde de novo. Agora, com a suíte verde, Refactor o laço de soma num stream().mapToInt(...).sum() e rodo os testes a cada passo. Lista vazia, fatia pronta — três ciclos, poucos minutos, três commits no verde.

O que esse exemplo demonstra

Repare que nenhuma das três estratégias foi escolhida por dogma: Obvious onde o código era trivial, Fake It onde a forma era incerta, triangulação no instante em que um caso novo matou a constante. A lista guiou a ordem; o verde frequente deu os checkpoints. Esse é o ciclo de verdade — não um ritual, mas uma sucessão de decisões pequenas e reversíveis.

Inside-out × outside-in

Há duas direções clássicas de atacar uma feature com TDD, e elas espelham as duas escolas de teste unitário que [[04 - Testes unitários]] discute.

  • Inside-out (Detroit / clássica) — você começa pelas unidades internas (entidades de domínio, lógica pura), testa cada uma com colaboradores reais, e vai montando pra fora até chegar na borda. O design cresce de dentro pra fora. Usa poucos dublês.
  • Outside-in (Londres / mockista) — você começa pela borda (o ponto de entrada, o caso de uso) e desce pra dentro. Como as camadas internas ainda não existem, você as substitui por mocks, descobrindo as interfaces que vai precisar. O design é puxado de fora pra dentro. Veja [[05 - Test doubles - dummy, stub, spy, mock, fake]] pra entender os dublês que sustentam esse estilo.
flowchart LR
    subgraph IO["Inside-out (Detroit)"]
        direction TB
        D1["Domínio<br/>(começa aqui)"] --> S1["Serviço"]
        S1 --> B1["Borda<br/>(termina aqui)"]
    end
    subgraph OI["Outside-in (Londres)"]
        direction TB
        B2["Borda<br/>(começa aqui)"] --> S2["Serviço<br/>(mock)"]
        S2 --> D2["Domínio<br/>(mock)"]
    end

Leitura do diagrama

No inside-out (esquerda), você sobe: começa pelo domínio com colaboradores reais e cresce em direção à borda. No outside-in (direita), você desce: começa pela borda e usa mocks pras camadas internas ainda inexistentes, descobrindo as interfaces no caminho. Mesma feature, direções opostas — e diferenças de quantos dublês você usa.

Nenhuma das duas é “a certa”. Muita gente mistura: outside-in pra descobrir as interfaces, inside-out pra preencher a lógica de domínio.

Double-loop TDD

Freeman e Pryce, no livro Growing Object-Oriented Software, Guided by Tests, descrevem o double-loop TDD (loop duplo). Há um loop externo de testes de aceitação (a feature inteira, na perspectiva do usuário) e um loop interno de testes de unidade. Você roda o loop interno na escala de minutos; o externo, na escala de horas a dias. O teste de aceitação fica vermelho até que vários ciclos Red-Green-Refactor de unidade o tornem verde — aí a fatia de funcionalidade está pronta. É um tema avançado; mencionado aqui só pra você reconhecer o nome.

Armadilhas comuns

O ciclo é simples de descrever, mas fácil de sabotar sem perceber. Aqui estão as cinco formas mais comuns de fazer isso, do primeiro teste ao último commit — a maioria delas mora exatamente nas transições entre os três passos, não dentro de um passo isolado.

Um teste que nunca falhou é suspeito

Se você escreve o código primeiro e o teste depois, e o teste passa de primeira, você não sabe se ele testa alguma coisa. Um teste que nunca esteve vermelho pode estar verificando o nada — um assert true disfarçado. Ver o vermelho é a prova de que o teste tem dentes.

Teste grande demais no Red

Se o teste cobre comportamento demais, o Red demora a virar verde — você fica longos minutos no vermelho, exatamente o estado que TDD existe pra minimizar. Quebre em passos menores.

Pular o Refactor

O ciclo “funciona” sem refatorar — os testes passam. Mas a duplicação e a bagunça se acumulam ciclo a ciclo, e a dívida vira juros compostos. O Refactor não é opcional; é onde o design é pago.

Refatorar com a barra vermelha

Refatorar é mudar a estrutura preservando o comportamento — e a prova de que o comportamento foi preservado é a suíte verde. Mexer no design com um teste vermelho é remover a rede no meio do salto: você não sabe mais se quebrou por causa do refactor ou do bug que já estava lá.

Otimizar no Green

Performance, caches, abstrações espertas — nada disso pertence ao Green. O Green quer o verde. Otimização prematura aqui é over-engineering com outro nome, e some o feedback rápido que justifica o ciclo.

Nenhuma dessas cinco armadilhas exige ferramenta nova pra evitar — todas se resolvem olhando pro estado do ciclo antes de agir: “estou vermelho ou verde agora? o que esse estado me autoriza a fazer?“.

Em entrevista

Como explicar TDD em inglês

“TDD is a tight loop: I write a failing test first (Red), write the minimum code to pass it (Green), then refactor under a green safety net. I keep the steps small — baby steps — so a mistake costs minutes, not hours. Seeing the test fail first matters: a test that never failed might be asserting nothing. When the implementation is obvious I just type it; when I’m unsure of the abstraction, I’ll fake it with a constant and then triangulate — add a second case that forces me to generalize instead of guessing the abstraction up front. I keep a running test list so the cases I still owe live on paper, not in my head, and I commit on every green so I always have a checkpoint to roll back to. For me the real payoff is design: the test is the first client of my API, so it pushes me toward testable, decoupled code with injected dependencies. I tend to mix outside-in to discover interfaces and inside-out to flesh out the domain logic.”

Vocabulário PT → EN

PortuguêsEnglish
vermelho-verde-refatorarred-green-refactor
ciclo apertadotight loop
passos de bebêbaby steps
finja até conseguirfake it till you make it
triangulaçãotriangulation
implementação óbviaobvious implementation
estratégias de greengreen-bar strategies
lista de testestest list
premissa de prioridade de transformaçãotransformation priority premise
commit no verdecommit on green
testar-commitar-revertertest && commit || revert (TCR)
ponto de checkpointcheckpoint
rede de segurançasafety net
de dentro pra forainside-out
de fora pra dentrooutside-in
teste de aceitaçãoacceptance test
loop duplodouble-loop TDD
código de produçãoproduction code
over-engineering / exagero de designover-engineering

Fontes

  • Kent Beck, Test-Driven Development by Example (2002) — fonte original do ciclo Red-Green-Refactor e das três estratégias (Fake It, Obvious Implementation, Triangulation).
  • Martin Fowler, “TestDrivenDevelopment” — definição concisa do ciclo e do framing de TDD como técnica de design.
  • Steve Freeman e Nat Pryce, Growing Object-Oriented Software, Guided by Tests (2009) — origem do double-loop TDD (loop externo de aceitação + loop interno de unidade) e do estilo outside-in/mockista.
  • Robert C. Martin, “The Transformation Priority Premise” (2013) — transformações ordenadas por complexidade; escolher a mais simples evita impasses no ciclo.
  • Kent Beck, “test && commit || revert” (2018) — fluxo TCR; commit automático no verde, revert automático no vermelho, forçando passos minúsculos.

O que vem a seguir

Esta nota ficou na mecânica: como o ciclo Red-Green-Refactor funciona por dentro, passo a passo, estratégia a estratégia. Duas perguntas continuam em aberto — perguntas que a mecânica sozinha não responde.

A primeira é de julgamento: quando vale a pena aplicar TDD, e quando o custo do ciclo supera o benefício — código exploratório, protótipos descartáveis, telas que mudam a cada reunião. Essa conversa, com o pragmatismo do dia a dia, é o assunto de [[09 - TDD na prática]].

A segunda é de ferramenta: como esse mesmo ciclo se materializa em Python, com pytest — fixtures no lugar de setup manual, parametrize no lugar de repetir o corpo do teste, e o próprio runner reforçando o ritmo Red-Green-Refactor. Veja [[03-Dominios/Tecnologia/Python/Testes/08 - TDD na prática com pytest]].

Nenhuma das duas notas repete a mecânica descrita aqui — o Red-Green-Refactor, as três estratégias de Green, a escada de transformações. Elas partem dela.

Se você chegou até aqui sem nunca ter feito um ciclo de verdade, o próximo passo natural não é ler mais — é abrir um editor, escolher uma função pequena e boba, e rodar os três passos uma vez. A mecânica só faz sentido no corpo depois que passa pela mão.

Veja também

  • [[04 - Testes unitários]] — a unidade que você coloca na bancada; o teste como primeiro cliente da API.
  • [[05 - Test doubles - dummy, stub, spy, mock, fake]] — os dublês que sustentam o estilo outside-in/mockista.
  • [[06 - Testar comportamento, não implementação]] — o que seus testes de TDD devem afirmar pra não travar o Refactor.
  • [[09 - TDD na prática]] — quando TDD vale a pena, quando não vale, e o pragmatismo do dia a dia.
  • [[16 - Estratégia de testes em entrevista]] — como posicionar TDD numa conversa de entrevista.
  • [[03-Dominios/Engenharia/Testes/index|Testes]] — índice do galho.