Princípios de Teste
Referências Específicas de Linguagem
Para padrões de teste específicos de linguagem, leia também:
- TypeScript (Vitest/RTL/Playwright): references/typescript.md
Filosofia Central de Teste
- Testes são Código de Primeira Classe: Mantenha a qualidade do teste igual à do código de produção
- Feedback Rápido: Testes devem ser executados rapidamente e fornecer feedback imediato
- Confiabilidade: Testes devem ser determinísticos e reproduzíveis
- Independência: Cada teste deve ser executado de forma isolada
Processo TDD [OBRIGATÓRIO para todas as alterações de código]
Execute este processo para cada alteração de código:
Fase RED
PASSO 1: Escreva o teste que define o comportamento esperado PASSO 2: Execute o teste PASSO 3: Confirme que o teste FALHA (se passar, o teste está errado)
Fase GREEN
PASSO 1: Escreva o código MÍNIMO para fazer o teste passar PASSO 2: Execute o teste PASSO 3: Confirme que o teste PASSA
Fase REFACTOR
PASSO 1: Melhore a qualidade do código (elimine duplicação, melhore a nomenclatura) PASSO 2: Execute o teste PASSO 3: Confirme que o teste AINDA PASSA
Fase VERIFY [OBRIGATÓRIO - 0 ERROS REQUERIDOS]
PASSO 1: Execute TODOS os comandos de verificação de qualidade para sua linguagem/projeto PASSO 2: Corrija quaisquer erros até que TODOS os comandos passem com 0 erros PASSO 3: Confirme que não há regressões
APLICAÇÃO: Não é possível prosseguir para a próxima fase com QUALQUER falha na verificação de qualidade
Exceções ao TDD (TDD não necessário)
- Arquivos de configuração puros
- Apenas documentação
- Correções de emergência (mas adicione testes imediatamente após)
- Sprints exploratórios (descarte ou reescreva com testes antes de mesclar)
- Scripts de build/implantação (a menos que contenham lógica de negócio)
Requisitos de Qualidade [OBRIGATÓRIO]
Cobertura
- Trate a cobertura como um sinal de diagnóstico para encontrar áreas não testadas, não como uma meta. Metas são manipuladas em testes triviais.
- Concentre os testes em caminhos críticos, lógica de negócio e comportamento cuja regressão seria importante.
- Priorize asserções significativas em vez do número de cobertura. Qualquer limite exigido vem do CI do projeto, arquivo de tarefa, plano de trabalho ou Documento de Design.
Características do Teste
Todos os testes DEVEM ser:
- Independentes: Sem dependências entre testes
- Reproduzíveis: A mesma entrada sempre produz a mesma saída
- Rápidos: Conclua a suíte de testes completa dentro da janela de feedback aceita pelo projeto e sinalize suítes que retardam materialmente a iteração local ou o CI
- Auto-verificáveis: Aprovação/reprovação clara sem verificação manual
- Oportunos: Escritos perto do código que testam
APLICAÇÃO: Testes que falharem em QUALQUER característica DEVEM ser corrigidos imediatamente
Tipos de Teste
Testes Unitários
Propósito: Testar componentes individuais isoladamente
Características:
- Testam uma única função, método ou classe
- Execução rápida (milissegundos)
- Sem dependências externas
- Simulam (mock) serviços externos
- Maioria da sua suíte de testes
Testes de Integração
Propósito: Testar interações entre componentes
Características:
- Testam múltiplos componentes juntos
- Podem incluir banco de dados, sistema de arquivos ou APIs
- Mais lentos que testes unitários
- Verificam contratos entre módulos
- Porção menor da suíte de testes
Testes Ponta a Ponta (E2E)
Propósito: Testar fluxos de trabalho completos da perspectiva do usuário
Características:
- Testam toda a pilha da aplicação
- Simulam interações reais do usuário
- Tipo de teste mais lento
- Menor em número
- Maior nível de confiança
Pirâmide de Testes
Siga a estrutura da pirâmide de testes:
/\ <- Poucos testes E2E (Alta confiança, lentos)
/ \
/ \ <- Alguns testes de Integração (Confiança média, velocidade média)
/ \
/________\ <- Muitos testes Unitários (Rápidos, fundamentais)
Princípios de Design de Testes
Padrão AAA (Arrange-Act-Assert)
Estruture cada teste em três fases claras:
// Arrange: Configurar dados e condições de teste
user = createTestUser()
validator = createValidator()
// Act: Executar o código sob teste
result = validator.validate(user)
// Assert: Verificar o resultado esperado
assert(result.isValid == true)
Uma Asserção Por Conceito
- Teste um comportamento por caso de teste
- Múltiplas asserções são OK se testarem um único conceito
- Separe asserções não relacionadas em testes separados — um teste DEVE verificar um comportamento
Nomes Descritivos de Teste
Os nomes dos testes devem descrever claramente:
- O que está sendo testado
- Sob quais condições
- Qual é o resultado esperado
Formato recomendado: "deve [comportamento esperado] quando [condição]"
Independência dos Testes
Requisitos de Isolamento
- Cada teste cria seus próprios dados de teste
- Sem dependências na ordem de execução
- Limpar o próprio estado
- Passar quando executados isoladamente
Setup e Teardown
- Use hooks de setup para preparar o ambiente de teste
- Use hooks de teardown para limpar recursos
- Mantenha o setup restrito aos dados, dependências e fixtures necessários para o comportamento sob teste
- Garanta que o teardown seja executado mesmo se o teste falhar
Mocking e Dublês de Teste
Quando Usar Mocks
- Mock de dependências externas: APIs, bancos de dados, sistemas de arquivos
- Mock de operações lentas: Chamadas de rede, computações pesadas
- Mock de comportamento imprevisível: Valores aleatórios, hora atual
- Mock de serviços indisponíveis: Serviços de terceiros
Princípios de Mocking [OBRIGATÓRIO]
- Faça mock nas fronteiras, não internamente — use implementações reais para utilidades internas
- Mantenha cada mock limitado ao comportamento que o teste precisa controlar ou observar
- Verifique as expectativas do mock quando relevante
- Use adaptadores para bibliotecas/frameworks externos que você não controla
Tipos de Dublês de Teste
- Stub: Retorna valores predeterminados
- Mock: Verifica se foi chamado corretamente
- Spy: Registra informações sobre chamadas
- Fake: Implementação funcional simplificada
- Dummy: Passado, mas nunca usado
Teste da Camada de Dados
Limitações de Mock para Acesso a Dados
Mocks validam padrões de chamada, mas não validam correção de esquema, correção de consulta ou restrições de armazenamento. Exemplos de problemas que mocks podem perder:
- deriva de esquema (schema drift)
- incompatibilidade de colunas ou campos
- junções (joins), filtros ou agregações incorretos
- incompatibilidade de migração
Quando a Verificação Real da Camada de Dados Agrega Valor
Use verificação de acesso a dados real ou semelhante à produção ao testar:
- implementações de repositório ou DAO
- mapeamentos ORM
- construtores de consulta ou SQL bruto
- comportamento de persistência que depende de restrições ou formato do esquema
Opções de Ambiente
Escolha a opção mais prática para o ambiente do projeto:
- banco de dados containerizado
- banco de dados de teste dedicado
- banco de dados em memória com limitações documentadas
- harness de teste local baseado em adaptador
Alinhamento de Design
Quando um Documento de Design incluir Fronteiras de Teste, siga-o como base para decidir quais dependências permanecem reais e quais fronteiras são isoladas.
Práticas de Qualidade de Teste [OBRIGATÓRIO]
Mantenha os Testes Ativos
- Corrija ou exclua testes com falha: Resolva as falhas imediatamente
- Remova testes comentados: Corrija-os ou exclua-os totalmente
- Mantenha os testes em execução: Testes quebrados perdem valor rapidamente
- Mantenha a suíte de testes: Refatore os testes conforme necessário
Qualidade do Código de Teste
- Aplique os mesmos padrões do código de produção
- Use nomes de variáveis descritivos
- Extraia helpers de teste para reduzir duplicação
- Mantenha os testes legíveis e fáceis de manter
Helpers e Utilitários de Teste
- Crie construtores de dados de teste reutilizáveis
- Extraia configurações comuns em funções helper
- Crie utilitários de teste para cenários complexos
- Compartilhe helpers entre arquivos de teste adequadamente
O Que Testar
Foco no Comportamento
Teste o comportamento observável, não a implementação:
- Bom: Teste se a função retorna a saída esperada
- Bom: Teste se o endpoint correto da API é chamado
- Ruim: Teste se uma variável interna foi definida
- Ruim: Teste a ordem das chamadas de métodos privados
Teste Casos Limite
Sempre teste:
- Condições de contorno: Valores mín/máx, coleções vazias
- Casos de erro: Entrada inválida, valores nulos, dados ausentes
- Casos limite: Caracteres especiais, valores extremos
- Caminho feliz: Uso normal e esperado
Critérios de Qualidade de Teste [OBRIGATÓRIO]
- Expectativas literais: Use valores literais codificados em asserções — valor esperado ≠ valor de retorno do mock (a implementação processa dados)
- Verificação de resultado: Afirme valores de retorno e estado, não a ordem de chamada
- Asserções significativas: TODO teste DEVE ter pelo menos uma asserção — um teste sem asserções não fornece valor algum
- Mock apenas de E/S externa: Mock de DB/API/sistema de arquivos, use utilidades internas reais
- Cobertura de contorno: Inclua casos vazio/zero/máximo/erro junto com os caminhos felizes
APLICAÇÃO: Testes que violarem QUALQUER critério DEVEM ser reescritos
Requisitos de Verificação [OBRIGATÓRIO para fase VERIFY]
Lista de Verificação Antes do Commit
☐ Todos os testes passam ☐ Nenhum teste ignorado ou comentado ☐ Nenhum código de depuração deixado nos testes ☐ Limite de cobertura é atingido quando o projeto, arquivo de tarefa, plano de trabalho ou Documento de Design define um ☐ Testes executam em tempo razoável
Política de Tolerância Zero
- Zero testes com falha: Corrija imediatamente
- Zero testes ignorados: Exclua ou corrija
- Zero testes instáveis: Torne-os determinísticos
- Zero testes lentos: Otimize ou divida
APLICAÇÃO: Não é possível prosseguir com a conclusão da tarefa se QUALQUER verificação de qualidade falhar
Organização dos Testes
Estrutura de Arquivos
- Espelhe a estrutura de produção: Os testes seguem a organização do código
- Convenções de nomenclatura claras: Siga os padrões de arquivos de teste do projeto
- Agrupamento lógico: Agrupe testes relacionados juntos
- Separe tipos de teste: Testes unitários, de integração, e2e em diretórios separados
Organização da Suíte de Testes
tests/
├── unit/ # Testes unitários rápidos e isolados
├── integration/ # Testes de integração
├── e2e/ # Testes ponta a ponta
├── fixtures/ # Dados de teste e fixtures
└── helpers/ # Utilitários de teste compartilhados
Considerações de Desempenho
Velocidade do Teste
- Testes unitários: < 100ms cada
- Testes de integração: < 1s cada
- Suíte completa: Deve ser executada com frequência (< 10 minutos)
Antipadrões Comuns
Detecte e elimine esses padrões imediatamente:
- Testes que não testam nada (sempre passam)
- Testes que dependem da ordem de execução
- Testes que dependem de estado externo
- Testes com lógica complexa (testes que precisam de seus próprios testes)
- Testar detalhes de implementação em vez de comportamento observável
- Mocking excessivo (mock apenas nas fronteiras, use internos reais)
- Duplicação de código de teste
Testes Instáveis
Elimine testes que falham intermitentemente:
- Remova dependências de tempo
- Use dados determinísticos em vez de valores aleatórios
- Garanta a limpeza adequada
- Corrija condições de corrida
- Torne todos os testes determinísticos
Teste de Regressão
- Adicione um teste para cada correção de bug
- Mantenha uma suíte de testes abrangente
- Execute a suíte completa regularmente
- Exclua um teste apenas quando o comportamento coberto não existir mais ou o mesmo comportamento for coberto por um teste mais forte no nível correto
Código Legado
- Adicione testes de caracterização antes de refatorar
- Teste o comportamento existente primeiro
- Melhore a cobertura gradualmente
- Refatore com confiança