Testes a partir de Specs — TDD com Inteligência Artificial
Baixar PDFComo usar testes como back-pressure para agentes de IA. Red/Green TDD, geração de testes a partir de specs, coverage como métrica e padrões práticos.
A qualidade do código gerado por IA é proporcional à qualidade dos testes. Sem testes, o agente gera código que "parece funcionar". Com testes, o agente gera código que funciona de verdade — porque os testes são o gate de validação.
Testes não são uma etapa final. São o ponto de partida.
O princípio do Back-Pressure
"Tests are the primary quality gate in the agent loop." — Geoffrey Huntley
Back-pressure é qualquer mecanismo que força o agente a validar o próprio output. Quanto mais back-pressure, maior a qualidade:
Nível 1: Nenhum test
→ Agente gera código que "parece certo"
→ Alucina com confiança
→ 60% de chance de funcionar
Nível 2: Lint + typecheck
→ Código compila/formata
→ Mas comportamento não é validado
→ 75% de chance de funcionar
Nível 3: Testes unitários
→ Comportamento validado
→ Mas integração não testada
→ 90% de chance de funcionar
Nível 4: Testes unitários + integração + lint + build
→ Código validado em múltiplos níveis
→ Agente é "pressionado" a corrigir antes de avançar
→ 98% de chance de funcionarRed/Green TDD com IA (Simon Willison)
O padrão mais eficaz documentado por Simon Willison:
Fluxo
1. Escreva testes a partir da spec (RED — testes falham)
2. Rode os testes — confirme que falham
3. Peça à IA para implementar até testes passarem (GREEN)
4. Peça à IA para adicionar testes de edge cases
5. Rode todos os testes novamente
6. CommitExemplo prático
Spec (specs/auth.md):
## POST /api/register
- Input: { email: string, password: string, name: string }
- Output: { id: string, email: string, createdAt: string }
- Validações:
- email deve ser formato válido
- password mínimo 8 caracteres
- name não pode ser vazio
- Erros:
- 400: validação falhou
- 409: email já cadastradoPasso 1 — Escreva testes (você, não a IA):
// src/__tests__/auth-register.test.ts
import { describe, it, expect } from 'vitest';
describe('POST /api/register', () => {
it('retorna 201 com dados válidos', async () => {
const res = await register({
email: '[email protected]',
password: 'secure123',
name: 'Kaique',
});
expect(res.status).toBe(201);
expect(res.body).toHaveProperty('id');
expect(res.body.email).toBe('[email protected]');
});
it('retorna 400 sem email', async () => {
const res = await register({ password: 'secure123', name: 'Kaique' });
expect(res.status).toBe(400);
});
it('retorna 400 com password < 8 chars', async () => {
const res = await register({
email: '[email protected]',
password: 'short',
name: 'Kaique',
});
expect(res.status).toBe(400);
});
it('retorna 409 com email duplicado', async () => {
await register({ email: '[email protected]', password: 'secure123', name: 'A' });
const res = await register({ email: '[email protected]', password: 'secure456', name: 'B' });
expect(res.status).toBe(409);
});
});Passo 2 — Rode (RED):
pnpm vitest run src/__tests__/auth-register.test.ts
# ✗ todos falham (função register não existe)Passo 3 — Peça à IA:
Read specs/auth.md and src/__tests__/auth-register.test.ts.
Implement the register function so all tests pass.
Do not modify the tests.Passo 4 — Rode (GREEN):
pnpm vitest run src/__tests__/auth-register.test.ts
# ✓ todos passamGerando testes a partir de specs com IA
Você pode pedir à IA para escrever os testes — mas valide-os antes de pedir a implementação.
Prompt para gerar testes
Read specs/auth.md.
Generate a comprehensive test file for the POST /api/register endpoint.
Requirements:
- Use Vitest (never Jest)
- Cover: happy path, validation errors, duplicate handling
- Use descriptive test names in Portuguese
- Export the test file to src/__tests__/auth-register.test.ts
Do NOT implement the endpoint. Only write tests.Validando testes gerados pela IA
Sempre revise os testes gerados antes de pedir implementação:
- Cobrem todos os cenários da spec? — compare com a lista de "Testes esperados"
- Usam a framework correta? — Vitest, não Jest
- Edge cases estão presentes? — input vazio, null, overflow
- Não há testes vazios? — a IA às vezes gera
it.todo()sem conteúdo - Nomes são descritivos? —
retorna 400 sem email>test validation
Coverage como métrica de qualidade
Coverage não é perfeito, mas é o melhor proxy que temos para "a IA cobriu os cenários?"
Configurando coverage por módulo
// vitest.config.ts
export default defineConfig({
test: {
coverage: {
provider: 'v8',
thresholds: {
statements: 80,
branches: 75,
functions: 80,
lines: 80,
},
include: ['src/**/*.ts'],
exclude: ['src/**/*.test.ts', 'src/**/*.d.ts'],
},
},
});No loop do agente
Inclua no PROMPT.md:
After implementing, run: pnpm vitest run --coverage
If coverage for the new module drops below 80%, add more tests before committing.Testes de regressão
Quando a IA refatora código, testes de regressão garantem que o comportamento não mudou.
Padrão: testes de snapshot para APIs
it('schema de resposta não mudou', async () => {
const res = await register({
email: '[email protected]',
password: 'secure123',
name: 'Snapshot Test',
});
expect(res.body).toMatchObject({
id: expect.any(String),
email: '[email protected]',
createdAt: expect.any(String),
});
// Campos que NÃO devem existir
expect(res.body).not.toHaveProperty('password');
expect(res.body).not.toHaveProperty('__v');
});Back-pressure além de testes
Qualquer verificação automatizada é back-pressure:
| Tipo | Comando | O que valida |
|---|---|---|
| Lint | pnpm lint | Formatação e padrões de código |
| Typecheck | pnpm tsc --noEmit | Tipos TypeScript corretos |
| Testes unitários | pnpm vitest run | Comportamento de funções |
| Testes E2E | pnpm test:e2e | Fluxos completos do usuário |
| Build | pnpm build | O código compila para produção |
| Security scan | npm audit | Dependências vulneráveis |
| Static analysis | eslint --max-warnings 0 | Zero warnings tolerados |
No CLAUDE.md
## After EVERY code change:
1. pnpm lint:fix
2. pnpm format
3. pnpm vitest run
4. If all pass, commit with Conventional Commits
## NEVER commit if:
- Any test fails
- Lint has errors
- TypeScript has type errorsErros comuns
| Erro | Impacto | Correção |
|---|---|---|
| Pedir código sem testes | Agente alucina com confiança | Sempre escreva testes primeiro |
| Testes gerados pela IA sem revisão | Testes podem não cobrir cenários reais | Revise antes de pedir implementação |
| Testes que testam implementação, não comportamento | Refatoração quebra testes | Teste outputs, não internals |
| Coverage baixo ignorado | Bugs em código não testado | Threshold mínimo de 80% |
| Sem back-pressure no loop | Agente acumula dívida técnica | Lint + testes + build em TODO commit |
Conteúdo Relacionado
Spec-Driven Development — Escreva Specs que a IA Executa
Como escrever especificações estruturadas que guiam agentes de IA para gerar código correto. Métodos Ralph, CLAUDE.md, templates práticos e exemplos reais.
Economia de Tokens — Context Window como Recurso Finito
Como otimizar o uso de tokens em workflows com IA. Fresh context, subagentes, chunking de tarefas, effort levels e como reduzir custo sem perder qualidade.