November 29, 2025 (4mo ago) — last updated January 2, 2026 (3mo ago)

Red‑Green‑Refactor TDD: Guia Prático

Domine o ciclo Red‑Green‑Refactor do TDD com exemplos práticos em React/TypeScript e técnicas para código mais limpo e previsível.

← Back to blog
Cover Image for Red‑Green‑Refactor TDD: Guia Prático

O ciclo Red‑Green‑Refactor do TDD transforma design em pequenos passos verificáveis: escreva um teste que falha, implemente o mínimo para passar e então refatore com segurança. Este guia prático mostra o fluxo, exemplos em React/TypeScript e como TDD traz valor técnico e de negócio.

Red‑Green‑Refactor TDD: Guia Prático

Resumo: Domine o ciclo Red‑Green‑Refactor de Test‑Driven Development (TDD) com um fluxo prático, exemplos em React/TypeScript e benefícios de negócio que ajudam a manter código limpo e confiável.

Introdução

O ciclo Red‑Green‑Refactor do Test‑Driven Development (TDD) é um processo simples e disciplinado que guia o design do software. Comece escrevendo um teste que falha (Red), escreva o código mínimo para fazê‑lo passar (Green) e então limpe a implementação (Refactor). Repetir esse ciclo converte incerteza em passos pequenos e verificáveis, reduzindo riscos e melhorando a qualidade do software desde cedo.1

O ritmo do desenvolvimento guiado por testes

Diagrama do ciclo Red‑Green‑Refactor

Muitos desenvolvedores pensam que TDD é só sobre testes, quando na prática é uma técnica de design. Escrever o teste primeiro obriga você a pensar em como o código será usado antes de implementá‑lo. Essa inversão reduz suposições e promove progresso em pequenos passos. O ciclo Red‑Green‑Refactor passa a ser o compasso do desenvolvimento confiável.

As três fases em poucas palavras

  • Fase Red (teste falhando): escreva um teste automatizado que descreva o menor comportamento útil. O teste deve falhar porque a implementação não existe.
  • Fase Green (fazer passar): implemente a menor quantidade de código necessária para satisfazer o teste. Priorize simplicidade para evitar over‑engineering.
  • Fase Refactor (melhorar o código): com os testes passando como rede de segurança, limpe nomes, remova duplicação e melhore a estrutura mantendo o comportamento.

Não pule a refatoração; ela evita acúmulo de dívida técnica e facilita mudanças futuras.

Resumo do ciclo

FasePropósitoObjetivo do desenvolvedor
RedDefinir requisito e validar o testeEscrever um teste pequeno que falhe
GreenSatisfazer o requisitoAdicionar o código mínimo para passar o teste
RefactorMelhorar qualidade internaLimpar duplicação e esclarecer intenção

Adotar essa cadência ajuda equipes a avançar de forma previsível. Em várias pesquisas sobre adoção ágil, equipes relatam benefícios de colaboração e qualidade ao incorporar práticas como TDD1.

Percorrendo o ciclo TDD na prática

Fluxo do processo TDD

Vamos construir um exemplo de UI: um componente LikeButton usando TypeScript, React e Jest. O exemplo mostra como TDD orienta o design mantendo comportamento previsível.

Fase Red: definir o primeiro requisito

Requisito inicial: o componente renderiza sem travar e exibe “Like”. Escrevemos o teste antes do componente.

// LikeButton.test.tsx
import React from "react";
import { render, screen } from "@testing-library/react";
import LikeButton from "./LikeButton";

describe("LikeButton", () => {
  it("renders a button with the initial text \"Like\"", () => {
    render(<LikeButton />);
    const likeButton = screen.getByRole("button", { name: /like/i });
    expect(likeButton).toBeInTheDocument();
  });
});

Executar o teste falha porque o componente ainda não existe. Esta é a fase Red — exatamente o que queremos.

Fase Green: o suficiente para passar

Crie o componente mínimo para satisfazer o teste.

// LikeButton.tsx
import React from "react";

const LikeButton = () => {
  return <button>Like</button>;
};

export default LikeButton;

Execute os testes novamente e eles passam. Missão cumprida para este ciclo.

Fase Refactor: polir a implementação

Agora limpe o código. Adicione tipos e estabeleça um padrão para expansão futura.

// LikeButton.tsx (refatorado)
import React, { FC } from "react";

type LikeButtonProps = {};

const LikeButton: FC<LikeButtonProps> = () => {
  return <button>Like</button>;
};

export default LikeButton;

Os testes continuam passando. A rede de segurança permite melhorar o código com confiança.

Iteração: clicar no botão

Novo requisito: clicar no botão altera seu texto para “Liked” e o desabilita para evitar múltiplos cliques. Comece com um teste que falha.

// LikeButton.test.tsx
it("changes text to \"Liked\" and becomes disabled when clicked", () => {
  render(<LikeButton />);
  const likeButton = screen.getByRole("button", { name: /like/i });
  fireEvent.click(likeButton);
  expect(likeButton).toHaveTextContent("Liked");
  expect(likeButton).toBeDisabled();
});

Implemente o comportamento mínimo para passar no teste.

// LikeButton.tsx
import React, { FC, useState } from "react";

type LikeButtonProps = {};

const LikeButton: FC<LikeButtonProps> = () => {
  const [liked, setLiked] = useState(false);
  const handleClick = () => setLiked(true);
  return (
    <button onClick={handleClick} disabled={liked}>
      {liked ? "Liked" : "Like"}
    </button>
  );
};

export default LikeButton;

Execute a suíte e tudo fica verde. Repita: um requisito pequeno por vez, protegido por testes.

O caso de negócio para qualidade de código

Balança comparando sem TDD e com TDD

Os benefícios técnicos do TDD se traduzem em valor de negócio. Menos defeitos em produção significam custos de suporte menores, menor churn de clientes e melhor reputação. Quando defeitos são detectados cedo, custam menos para corrigir; equipes podem gastar mais tempo criando funcionalidades que geram valor.2

Reduzindo defeitos pós‑release e custos de manutenção

Escrever testes antes do código força a adicionar apenas o que é necessário para satisfazer requisitos testáveis. Isso cria uma rede de segurança robusta e reduz regressões. Estudos empíricos mostram melhorias mensuráveis de qualidade e redução do esforço de depuração para equipes que aplicam TDD consistentemente2.

Acelerando o onboarding e melhorando a previsibilidade

Uma suíte de testes funciona como documentação executável. Novos desenvolvedores podem rodar os testes para entender o comportamento esperado do sistema em vez de depender de documentação desatualizada. Isso encurta o tempo de ramp‑up e reduz a carga sobre engenheiros seniores. Práticas de TDD também tornam estimativas e acompanhamento de progresso mais previsíveis, o que melhora o planejamento com stakeholders3.

Armadilhas comuns do TDD e como evitá‑las

TDD é simples de explicar, mas sutil de dominar. Os anti‑padrões abaixo costumam minar os benefícios.

Testes de integração embalados como unitários

Problema: o teste acaba exercitando muitas dependências — componentes, serviços, clientes de API e bancos de dados. O teste fica lento e frágil.

Solução: teste uma única unidade em isolamento. Use mocks, stubs e fakes para dependências externas. Se precisar de cobertura de integração, escreva testes de integração separados que rodem em uma suíte distinta.

Um teste unitário verdadeiro não deve tocar a rede, o sistema de arquivos ou um banco de dados real; sua velocidade e confiabilidade permitem refatorar com segurança4.

Testar implementação em vez de comportamento

Problema: os testes afirmam detalhes internos em vez do comportamento público. Testes quebram quando internals mudam, mesmo que o comportamento esteja correto.

Solução: foque na API pública e nos efeitos observáveis. Pergunte: dado este input, qual é o output esperado? Testes que verificam comportamento resistem a refatorações e continuam sendo documentação valiosa.

Pular a refatoração

Problema: desenvolvedores vão direto para a próxima funcionalidade depois de fazer os testes passarem, deixando implementações bagunçadas.

Solução: trate a refatoração como etapa obrigatória. Com os testes passando, pequenas limpezas são seguras e evitam acúmulo de problemas.

Integrando TDD à sua equipe e ao código legado

Equipe trabalhando com código legado

Adotar TDD é mudança cultural e técnica. Incentive aprendizado prático, inclua testes na Definição de Pronto e celebre vitórias orientadas por testes.

Promovendo TDD na equipe

Formas práticas de ganhar adesão:

  • Pair programming para guiar colegas pelo ciclo Red‑Green‑Refactor.
  • Mob programming para problemas complexos, rodiziando quem dirige para espalhar conhecimento.
  • Sessões de aprendizado que demonstrem TDD na base de código.

Comece pequeno e deixe que ganhos cedo se tornem prova do valor.

Domando código legado com testes de caracterização

Quando o código não tem testes e é arriscado de alterar, escreva testes de caracterização para documentar o comportamento atual. Esses testes permitem refatorar ou adicionar funcionalidades com confiança.

Automatizando qualidade com pipelines CI/CD

Execute a suíte de testes em cada commit no CI. Isso fornece feedback imediato, impõe gates de qualidade e torna a passagem dos testes obrigatória antes do merge. A automação mantém o loop de feedback rápido e confiável3.

Perguntas frequentes rápidas

O TDD substitui outros tipos de testes?

Não. TDD foca em testes unitários como ferramenta de design, mas você ainda precisa de testes de integração e end‑to‑end para validar interações entre componentes e fluxos completos de usuário.

Como usar TDD com bancos de dados ou APIs externas?

Isole dependências externas usando mocks, stubs ou fakes. Teste a lógica em isolamento e deixe testes de integração reais para uma suíte separada.

Vale a pena testar componentes simples de UI?

Sim, quando o teste verifica comportamento observável. Testes que afirmam o que o usuário vê e faz são úteis e resistentes a refatoração.

Perguntas e respostas — resumo em 3 pontos

P: Quanto tempo até minha equipe ver valor com TDD?

A: Ganhos aparecem rapidamente na redução de regressões; pequenas vitórias geralmente surgem em poucos sprints.

P: Qual é o menor primeiro passo para adotar TDD?

A: Exija um teste que falhe antes de implementar uma funcionalidade nova ou um bug não crítico, e imponha a refatoração.

P: Como convencer stakeholders a investir em testes?

A: Mostre economias a longo prazo — menos incidentes em produção e custos de manutenção menores — e exemplos concretos de problemas evitados.

1.
Digital.ai, “State of Agile Report,” https://digital.ai/resource-center/state-of-agile-report
2.
Basili, Victor R., et al., “An Empirical Study on the Effects of Test-Driven Development,” https://link.springer.com/article/10.1007/s10664-015-9378-2
3.
Google Cloud, “State of DevOps Report,” https://cloud.google.com/devops/state-of-devops
4.
Martin Fowler, “TestDrivenDevelopment,” https://martinfowler.com/bliki/TestDrivenDevelopment.html
← Back to blog
🙋🏻‍♂️

IA escreve código.
Você faz durar.

Na era da aceleração da IA, código limpo não é apenas uma boa prática — é a diferença entre sistemas que escalam e bases de código que entram em colapso sob seu próprio peso.