MÓDULO 3.5

🧪 Testando Camada por Camada

Por que testar primitivos isolados antes de compor — e como estruturar platform tests, smoke tests e E2E sintético.

📚

Tópicos

6

⏱️

Minutos

40

🧪

Tipo

Testes

1

🧪 Por que testar cada primitivo isolado

Quando primitivos são compostos sem teste individual, bugs em componentes específicos ficam ocultos pelo comportamento emergente da composição. Testar cada primitivo em isolamento significa: se algo falha, você sabe exatamente o que falhou.

Primitivo 1: Escrita atômica

Teste: escrever estado, matar processo no meio, confirmar que arquivo não está corrompido

Primitivo 2: Lockfile

Teste: iniciar duas instâncias simultâneas, confirmar que apenas uma executa

Primitivo 3: Fail-open

Teste: forçar erro no plugin, confirmar que Claude Code continua operando normalmente

2

🔬 Platform tests

Platform tests verificam as capacidades do ambiente de execução antes de qualquer build. São executados uma vez, antes do primeiro prompt, para confirmar que o ambiente suporta o que o plugin vai fazer.

Checklist de platform tests

#!/usr/bin/env bash
# platform_test.sh

echo "=== Platform Tests ==="

# Versão do bash
bash_version=$(bash --version | head -1)
echo "Bash: $bash_version"

# jq disponível (para JSON)
jq --version > /dev/null 2>&1 && echo "jq: OK" || echo "jq: MISSING"

# mkdir atômica (lockfile)
mkdir /tmp/test_atomic_lock 2>/dev/null && \
  rmdir /tmp/test_atomic_lock && \
  echo "Atomic mkdir: OK"

# mv atômico (write-then-rename)
echo "test" > /tmp/test_atomic.tmp && \
  mv /tmp/test_atomic.tmp /tmp/test_atomic && \
  rm /tmp/test_atomic && \
  echo "Atomic mv: OK"

echo "=== Done ==="
3

💨 Smoke tests

Smoke tests são o mínimo necessário para confirmar que uma camada não está obviamente quebrada. Rápidos, diretos, cobrindo apenas o happy path — não edge cases. São o gate mínimo entre prompts.

Smoke test por camada

Scaffold

Todos os arquivos esperados existem. O hook pode ser invocado sem erro.

Estado

Inicializar estado, ler estado, fazer transição — sem erros.

Lógica

Executar o fluxo principal de ponta a ponta com input mínimo.

Segurança

Forçar falha em cada caminho de erro e confirmar fail-open.

4

🎭 E2E sintético

E2E sintético simula o fluxo real do sistema com dependências substituídas por stubs controlados. Cobertura de fluxo completo, velocidade de teste unitário, sem dependência de serviços externos.

Estrutura de E2E sintético

# e2e_synthetic.sh
# Simula uma sessão completa sem Claude Code real

# Setup: estado inicial
echo '{"phase":"idle","version":1}' > /tmp/test_state.json

# Simula trigger do hook PreToolUse
./hooks/pre_tool_use.sh '{"tool":"Write"}' && echo "PreToolUse: OK"

# Simula Stop Hook fase 1 (planning)
./hooks/stop.sh '{"session_id":"test"}' && echo "Stop phase 1: OK"

# Simula Stop Hook fase 2 (running)
./hooks/stop.sh '{"session_id":"test"}' && echo "Stop phase 2: OK"

# Verificar estado final
phase=$(jq -r '.phase' /tmp/test_state.json)
[ "$phase" = "done" ] && echo "E2E: PASS" || echo "E2E: FAIL"

# Cleanup
rm /tmp/test_state.json
5

📊 O que fazer quando um teste falha no meio da sequência

Um teste que falha no prompt N não significa necessariamente que o prompt N está errado. O protocolo de diagnóstico identifica a camada real da falha antes de qualquer ação.

1

Replicar em isolamento

Isolar o comportamento que falhou. Remover todas as dependências externas e testar o componente específico de forma independente.

2

Bisect por camada

Testar as camadas anteriores individualmente. Se o smoke test da camada N-1 falha, o problema está nela — não no prompt atual.

3

Regredir apenas a camada com falha

Identificada a camada, regredir apenas ela. Preservar tudo que foi verificado. Re-executar o prompt com diagnóstico explícito no contexto.

6

🔄 Regressão

Regressão é re-executar os testes de todas as camadas anteriores após cada novo prompt. Garante que a nova camada não quebrou comportamentos já verificados — um risco real quando o modelo resolve a tarefa de uma forma que invalida suposições anteriores.

Suite de regressão mínima

#!/usr/bin/env bash
# regression.sh — executar após cada prompt

echo "=== Regression Suite ==="

# Camada 1: Scaffold
[ -f "hooks/pre_tool_use.sh" ] && echo "Scaffold: OK" || echo "Scaffold: FAIL"
[ -f "hooks/stop.sh" ] && echo "Stop hook: OK" || echo "Stop hook: FAIL"

# Camada 2: Estado
./test/state_init_test.sh && echo "State init: OK" || echo "State init: FAIL"
./test/state_transition_test.sh && echo "State transition: OK" || echo "State: FAIL"

# Camada 3: Primitivas de segurança
./test/fail_open_test.sh && echo "Fail-open: OK" || echo "Fail-open: FAIL"
./test/atomic_write_test.sh && echo "Atomic write: OK" || echo "Atomic write: FAIL"

echo "=== Done ==="

💡 Regressão como hábito

A suite de regressão deve ser executável em menos de 2 minutos para se tornar hábito. Se levar mais, ela será pulada sob pressão. Mantenha os testes rápidos — cobertura de intenção, não cobertura de linha.

Resumo do Módulo 3.5

Primitivos isolados primeiro — testar componentes antes de compor
Platform tests antecipam incompatibilidades — antes do primeiro prompt
Smoke test por camada — gate mínimo entre prompts
E2E sintético — fluxo completo sem dependências externas
Regressão após cada prompt — detectar quebras retroativas imediatamente

Próximo Módulo:

3.6 — Do Zero ao SPEC: Seu Próximo Projeto