Como se trabalha
10 · Testes
Três camadas. As duas primeiras usam as ferramentas da linguagem da stack (lacuna); a terceira é igual em toda stack. O que é comum a todas: TDD, dependências reais em container e um comando que roda tudo.
As três camadas
| Camada | O que prova | Velocidade | Roda em | Ferramentas |
|---|---|---|---|---|
| Unidade | O que prova: uma regra isolada | Velocidade: ms | Roda em: build, CI | Ferramentas: lacuna ({{LACUNA:testes.unidade}}) |
| Integração | O que prova: uma parte real do sistema contra dependências reais; inclui o teste de rota | Velocidade: s | Roda em: build, CI (precisa de Docker) | Ferramentas: lacuna ({{LACUNA:testes.integracao}}) |
| Fim a fim | O que prova: o usuário consegue, numa tela, de ponta a ponta | Velocidade: s–min por caso | Roda em: estação de trabalho (CI opcional) | Ferramentas: Playwright + Node (fixo) |
O teste de rota é o de integração mais comum: uma requisição HTTP atravessa, dentro do processo, o roteamento, a segurança e a resposta de uma aplicação, com usuário simulado e sem rede. Prova status, permissão e redirecionamento. Toda linguagem tem a sua ferramenta para isso; a da stack fica na ADR-0003 dela.
O que é fixo nas camadas de unidade e integração
Mesmo sem saber a linguagem, o modelo já decide:
- Um comando roda unidade + integração (ex.:
./gradlew build,npm test,dotnet test) e é o mesmo na máquina e na CI; - Dependências reais em container (Testcontainers ou equivalente da linguagem). Nada de banco em memória que finge ser outro (H2 no lugar de PostgreSQL), nem servidor OIDC falso para provar o fio com o Keycloak;
- A imagem do Keycloak nos testes é a mesma do
compose.yamle dotoolbox— conferido poreng/pinned-versions.sh; - Suporte de teste por aplicação (helpers de login, containers): duplicar um pouco é aceitável; extrair um módulo de suporte só quando a duplicação doer;
- Recortes documentados no
docs/guias/testes.md: só unidade (sem Docker), um módulo, uma classe, um teste; - Contratos da plataforma têm teste de integração em toda aplicação:
- identidade: rota protegida redireciona ao Keycloak; sem permissão → 403 explicativo; logout encerra a sessão no Keycloak;
- observabilidade: log JSON com
traceId; métricas só na porta interna;/upsem autenticação; coletor fora do ar não derruba requisição; - aviso de ambiente: aparece fora de
production.
Tempo de suíte
O Keycloak em container leva ~50 s para subir sozinho e mais de 3 min com vários em paralelo numa máquina de 4 CPUs — o startup é limitado por CPU. Regras:
- poucos testes de integração com Keycloak (o fio, não as regras), com espera generosa (6 min) e reuso do container dentro do módulo;
- regras de acesso testadas no teste de rota, com usuário simulado, não no Keycloak real;
- se a suíte ficar lenta, separar por tag (
unidade,integracao) é mudança de configuração, registrada no guia.
Fim a fim
O E2E tem documento próprio: 11 · Testes fim a fim hierárquicos.
Em resumo:
Matriz de quando rodar cada coisa
| Momento | Unidade | Integração | E2E |
|---|---|---|---|
A cada tarefa do tasks.md (ciclo TDD) | Unidade: o teste da tarefa | Integração: o teste da tarefa | E2E: o caso da tarefa, se ela muda uma tela |
| Ao terminar um grupo de tarefas | Unidade: módulo | Integração: módulo | E2E: casos da change |
| Ao terminar a change | Unidade: tudo | Integração: tudo | E2E: regressão: tudo, do zero |
| CI (push) | Unidade: tudo | Integração: tudo | E2E: opcional (ADR da stack) |
| Antes de um deploy | Unidade: — (a CI já rodou) | Integração: — | E2E: regressão na estação do mantenedor |
Roteiro manual
Um roteiro manual em prosa ao lado de um roteiro automatizado que o traduz são dois artefatos que se desencontram a cada change.
No modelo há uma fonte só: o caso E2E narra os próprios passos (step('…')), e
eng/e2e.sh --walkthrough gera o roteiro legível a partir deles — em Markdown, por
agrupamento e cenário, para quem quer conferir com as próprias mãos.