Desenvolvimento Orientado a Testes (TDD)
Idioma de saída
Por padrão, comunique-se com o usuário em português e redija estratégias de teste, descrições de teste e resumos de implementação em português. Quando o usuário especificar explicitamente outro idioma ou a documentação existente tiver convenções diferentes, siga essas convenções; código, comandos, nomes de produtos e citações que devem permanecer no original não devem ser traduzidos.
Filosofia
Princípio central: Testes devem verificar o comportamento através de interfaces públicas, não detalhes de implementação. O código pode mudar completamente; os testes não deveriam.
Testes bons são do tipo integração: eles exercitam caminhos de código reais através de APIs públicas. Eles descrevem o que o sistema faz, não como faz. Um bom teste lê como uma especificação – "usuário pode finalizar compra com carrinho válido" informa exatamente qual capacidade existe. Esses testes sobrevivem a refatorações porque não se importam com a estrutura interna.
Testes ruins estão acoplados à implementação. Eles simulam colaboradores internos, testam métodos privados ou verificam por meios externos (como consultar um banco de dados diretamente em vez de usar a interface). O sinal de alerta: seu teste quebra quando você refatora, mas o comportamento não mudou. Se você renomear uma função interna e os testes falharem, esses testes estavam testando implementação, não comportamento.
Veja tests.md para exemplos e mocking.md para diretrizes sobre simulação.
Anti-Padrão: Fatias Horizontais
NÃO escreva todos os testes primeiro, depois toda a implementação. Isso é "fatiamento horizontal" – tratar VERMELHO como "escrever todos os testes" e VERDE como "escrever todo o código".
Isso produz testes ruins:
- Testes escritos em lote testam comportamento imaginado, não comportamento real
- Você acaba testando a forma das coisas (estruturas de dados, assinaturas de funções) em vez do comportamento voltado ao usuário
- Os testes se tornam insensíveis a mudanças reais – passam quando o comportamento quebra, falham quando o comportamento está correto
- Você ultrapassa seus próprios limites, comprometendo-se com a estrutura de teste antes de entender a implementação
Abordagem correta: Fatias verticais através de tracer bullets. Um teste → uma implementação → repita. Cada teste responde ao que você aprendeu no ciclo anterior. Como você acabou de escrever o código, sabe exatamente qual comportamento importa e como verificá-lo.
ERRADO (horizontal):
VERMELHO: teste1, teste2, teste3, teste4, teste5
VERDE: impl1, impl2, impl3, impl4, impl5
CERTO (vertical):
VERMELHO→VERDE: teste1→impl1
VERMELHO→VERDE: teste2→impl2
VERMELHO→VERDE: teste3→impl3
...
Fluxo de trabalho
1. Planejamento
Ao explorar o código-fonte, leia CONTEXT.md (se existir) para que os nomes dos testes e o vocabulário da interface correspondam à linguagem de domínio do projeto, e respeite os ADRs na área que você está alterando.
Antes de escrever qualquer código:
- Confirme com o usuário quais mudanças de interface são necessárias
- Confirme com o usuário quais comportamentos testar (priorize)
- Identifique oportunidades para módulos profundos usando princípios de design de código-fonte quando os limites da interface não estiverem claros. Não invoque outra skill automaticamente a menos que o usuário peça explicitamente.
- Liste os comportamentos a serem testados (não etapas de implementação)
- Obtenha aprovação do usuário no plano
Pergunte: "Como deve ser a interface pública? Quais comportamentos são mais importantes de testar?"
Você não pode testar tudo. Confirme com o usuário exatamente quais comportamentos são mais importantes. Concentre o esforço de teste em caminhos críticos e lógica complexa, não em todos os casos de borda possíveis.
2. Tracer Bullet
Escreva UM teste que confirme UMA coisa sobre o sistema:
VERMELHO: Escreva teste para o primeiro comportamento → teste falha
VERDE: Escreva código mínimo para passar → teste passa
Este é seu tracer bullet – prova que o caminho funciona de ponta a ponta.
3. Loop incremental
Para cada comportamento restante:
VERMELHO: Escreva o próximo teste → falha
VERDE: Código mínimo para passar → passa
Regras:
- Um teste de cada vez
- Apenas código suficiente para passar no teste atual
- Não antecipe testes futuros
- Mantenha os testes focados no comportamento observável
4. Refatoração
Depois que todos os testes passarem, procure candidatos a refatoração:
- Extraia duplicação
- Aprofunde módulos (mova complexidade para trás de interfaces simples)
- Aplique princípios SOLID onde for natural
- Considere o que o novo código revela sobre o código existente
- Execute testes após cada etapa de refatoração
Nunca refatore enquanto estiver VERMELHO. Alcance VERDE primeiro.
Checklist por ciclo
[ ] O teste descreve comportamento, não implementação
[ ] O teste usa apenas a interface pública
[ ] O teste sobreviveria a uma refatoração interna
[ ] O código é mínimo para este teste
[ ] Nenhum recurso especulativo foi adicionado