Kaique Mitsuo Silva Yamamoto
IaDesenvolvimento com ia

Testes a partir de Specs — TDD com Inteligência Artificial

Como 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 funcionar

Red/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. Commit

Exemplo 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á cadastrado

Passo 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 passam

Gerando 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:

  1. Cobrem todos os cenários da spec? — compare com a lista de "Testes esperados"
  2. Usam a framework correta? — Vitest, não Jest
  3. Edge cases estão presentes? — input vazio, null, overflow
  4. Não há testes vazios? — a IA às vezes gera it.todo() sem conteúdo
  5. 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:

TipoComandoO que valida
Lintpnpm lintFormatação e padrões de código
Typecheckpnpm tsc --noEmitTipos TypeScript corretos
Testes unitáriospnpm vitest runComportamento de funções
Testes E2Epnpm test:e2eFluxos completos do usuário
Buildpnpm buildO código compila para produção
Security scannpm auditDependências vulneráveis
Static analysiseslint --max-warnings 0Zero 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 errors

Erros comuns

ErroImpactoCorreção
Pedir código sem testesAgente alucina com confiançaSempre escreva testes primeiro
Testes gerados pela IA sem revisãoTestes podem não cobrir cenários reaisRevise antes de pedir implementação
Testes que testam implementação, não comportamentoRefatoração quebra testesTeste outputs, não internals
Coverage baixo ignoradoBugs em código não testadoThreshold mínimo de 80%
Sem back-pressure no loopAgente acumula dívida técnicaLint + testes + build em TODO commit

Conteúdo Relacionado

On this page