O que Test-Driven Development faz?
Princípio central
A mudança de comportamento só merece confiança quando um teste falhou primeiro pelo motivo correto e depois passou devido à implementação.
Os testes devem verificar o comportamento por meio de interfaces públicas, não de detalhes de implementação. O código pode mudar completamente; os testes não devem.
Testes bons são do tipo integração: eles exercitam caminhos de código reais por meio de APIs públicas. Eles descrevem o que o sistema faz, não como faz. Um bom teste se lê como uma especificação: "usuário pode finalizar compra com carrinho válido" diz exatamente qual capacidade existe. Esses testes sobrevivem a refatorações porque não se importam com a estrutura interna.
Testes ruins são acoplados à implementação. Eles simulam (mock) colaboradores internos, testam métodos privados, verificam contagens de chamadas ou validam por meios externos em vez da interface pública. Sinal de alerta: o teste quebra após uma refatoração mesmo que o comportamento permaneça o mesmo.
Veja tests.md, mocking.md e testing-anti-patterns.md.
Regra de ferro
Nenhuma alteração de comportamento em produção sem um teste que falhe primeiro.
Significado:
- Escreva um teste para um comportamento.
- Execute-o e veja-o falhar.
- Confirme que a falha prova o comportamento ausente, não um erro de digitação/configuração.
- Escreva a menor alteração de produção que o faça passar.
- Refatore somente depois de verde (passando).
Se o código de implementação já existir antes de um teste:
- Não exclua o trabalho do usuário sem permissão.
- Trate-o como um esboço/referência, não como implementação validada.
- Prefira colocá-lo de lado, escrever o teste com falha e depois implementar a partir do teste.
- Se for necessário preservar o código existente, adicione primeiro um teste de regressão/caracterização e depois altere o comportamento com um novo teste com falha.
Anti-padrão: fatias horizontais
Não escreva todos os testes primeiro e depois toda a implementação. Isso é fatiamento horizontal.
Errado:
VERMELHO: teste1, teste2, teste3, teste4
VERDE: impl1, impl2, impl3, impl4
Certo:
VERMELHO -> VERDE -> REFATORAR: comportamento 1
VERMELHO -> VERDE -> REFATORAR: comportamento 2
VERMELHO -> VERDE -> REFATORAR: comportamento 3
Por quê: testes em lote codificam um design imaginado, ultrapassam o feedback e frequentemente testam formas em vez de comportamentos.
Fluxo de trabalho
1. Planeje o comportamento
Antes de escrever código:
- Confirme as alterações na interface pública com o usuário quando não forem óbvias.
- Liste os comportamentos a testar, não as etapas de implementação.
- Priorize caminhos críticos e lógica complexa; não busque completeza falsa.
- Identifique oportunidades para módulos profundos.
- Projete interfaces para testabilidade.
- Escolha o primeiro comportamento de bala-traçadora.
Pergunte: "Qual comportamento público deve existir? Qual comportamento importa primeiro?"
2. VERMELHO: um teste com falha
Escreva um teste mínimo para um comportamento observável.
Requisitos:
- Usa apenas a interface pública.
- O nome descreve o comportamento.
- Testa código real sempre que prático.
- Simula (mock) apenas em fronteiras do sistema ou em pontos de emenda inevitáveis.
- Falha antes da implementação.
Execute o comando mais restrito útil, por exemplo:
npm test path/to/test.test.ts
Verifique a falha:
- O teste falha, não há erros de configuração/digitação.
- O motivo da falha corresponde ao comportamento ausente.
- Se passar imediatamente, o teste está errado ou o comportamento já existe. Corrija o teste ou escolha o próximo comportamento ausente.
3. VERDE: implementação mínima
Escreva apenas código suficiente para passar no teste atual.
Não faça:
- Adicionar funcionalidades especulativas.
- Refatorar código não relacionado.
- Adicionar opções futuras.
- Ampliar o escopo porque "é fácil enquanto está aqui".
Execute:
npm test path/to/test.test.ts
Depois execute os testes relevantes ao redor. A saída deve estar limpa: sem novos avisos, instabilidades ou erros ocultos.
4. REFATORAR: limpe enquanto está verde
Refatore somente depois que os testes passarem. Se nenhuma refatoração for útil, diga isso brevemente e continue.
Procure por candidatos a refatoração:
- duplicação
- nomes ruins
- módulos rasos
- fronteiras confusas
- complexidade que pode ser movida para trás de uma interface pequena
Regras:
- O comportamento e as expectativas não mudam.
- Os testes permanecem verdes após cada etapa de refatoração.
- Refatorações de teste podem renomear, eliminar duplicação, extrair fixtures/builders ou melhorar mensagens de falha.
- Se uma asserção alterar o comportamento esperado, pare: isso é um novo ciclo VERMELHO.
5. Repita verticalmente
Escolha o próximo comportamento com base no que o último ciclo ensinou. Um comportamento de cada vez.
Lista de verificação por ciclo
[ ] O teste descreve comportamento observável, não implementação
[ ] O teste usa apenas a interface pública
[ ] O teste falhou antes da implementação
[ ] O motivo da falha estava correto
[ ] O código é mínimo para este teste
[ ] Nenhum comportamento especulativo foi adicionado
[ ] Testes relevantes passam de forma limpa
[ ] Refatoração considerada apenas quando verde
Gates de commit
Para trabalho auditável, faça commit das fases separadamente quando prático:
- Commit VERMELHO: teste apenas ou estrutura mínima mais asserção com falha. O corpo registra o comando que falhou e o motivo.
- Commit VERDE: implementação mínima. O corpo registra que o teste segmentado passou e que a refatoração foi considerada.
- Commit REFATORAR: nenhuma alteração de comportamento ou expectativa. O corpo informa o que mudou e o que permaneceu inalterado.
Não inclua atribuição de IA nos commits.
Testes de contrato de CLI
Para ferramentas de CLI, a superfície de comando é o contrato do produto. Prefira testes de fora para dentro no nível confiável mais baixo:
- Testes de contrato de CLI: execute comandos raiz/subcomandos com provedores falsos ou fixtures; verifique stdout, stderr, comportamento de saída, formato JSON.
- Testes unitários: análise, comparação, classificação, seleção de contexto, classificação de erros.
- Testes de integração de provedores: fixtures de sistema de arquivos e serviços externos falsos; sem rede/auth.
- Testes de fumaça ao vivo: opt-in apenas; verifique forma/invariantes, não saída exata volátil.
Regra de regressão de QA manual
QA manual é descoberta, não espinha dorsal de validação. Quando encontra uma lacuna de comportamento:
- Escreva o teste de regressão VERMELHO de nível mais baixo que a reproduza.
- Verifique a evidência da falha.
- Implemente VERDE.
- Reexecute os testes automatizados.
- Reexecute o QA manual somente depois que os testes passarem.
Se a saída/cópia/forma da CLI mudou, adicione ou atualize um teste de contrato de CLI.
Armadilhas de racionalização
| Afirmação | Resposta |
|---|---|
| "Muito simples para testar" | Comportamento simples ainda pode regredir. Adicione o teste pequeno. |
| "Vou testar depois" | Testes que passam depois não provam que o teste pode falhar. |
| "Eu verifiquei manualmente" | Verificações manuais não são testes de regressão repetíveis. |
| "Preciso explorar primeiro" | Tudo bem. Esboce, depois coloque de lado e comece TDD. |
| "O teste é difícil" | A interface pode ser difícil de usar. Simplifique o ponto de emenda/design. |
| "Mockar torna fácil" | Talvez esteja testando comportamento do mock. Leia anti-padrões. |
| "Um teste grande cobre tudo" | Prefira um comportamento por teste, a menos que o contrato ponta a ponta exija mais. |
| "Refatoração precisa de teste com falha" | Refatoração pura começa verde e permanece verde; mudança de comportamento precisa de VERMELHO. |
Bandeiras vermelhas: pare e corrija
- Comportamento de produção alterado antes do teste com falha.
- Teste passa imediatamente, mas é declarado como VERMELHO.
- Motivo da falha não inspecionado.
- Nome do teste descreve implementação.
- Teste verifica chamadas privadas, ordem de chamadas ou colaboradores internos.
- Configuração de mock domina a lógica do teste.
- Novo método existe apenas para testes.
- Corrigir o teste durante VERDE porque a implementação discorda.
- Lote horizontal de testes antes de qualquer implementação.
Quando estiver travado
| Problema | Ação |
|---|---|
| Não sei como testar | Escreva a API pública desejada e a primeira asserção. |
| Configuração do teste enorme | Extraia fixture/helper; se ainda for enorme, simplifique o design. |
| Preciso mockar tudo | O código provavelmente está muito acoplado. Introduza injeção de dependência/ponto de emenda. |
| Código existente não tem testes | Adicione teste de caracterização para o comportamento atual, depois VERMELHO para a mudança. |
| Bug não está claro | Reproduza manualmente/logs primeiro, depois codifique a menor regressão com falha. |
Verificação antes de finalizar
- Comportamentos novos/alterados têm testes.
- Cada teste de comportamento novo foi observado falhando pelo motivo correto.
- Todos os testes relevantes passam.
- Testes verificam comportamento público.
- Mocks são apenas em fronteiras ou justificados.
- Nenhuma API de produção exclusiva para testes foi adicionada.
- Descobertas de QA manual se tornaram testes de regressão.