Testes web que protegem o que importa

A melhor estratégia não é a que possui mais testes. É a que detecta cedo as falhas que causariam maior impacto ao produto.

Comece pela falha que não pode chegar ao usuário Uma estratégia de testes não deve começar pela pergunta: Qual porcentagem de cobertura precisamos atingir? Comece por: Quais falhas causariam maior dano se escapassem? Em uma loja virtual, riscos críticos podem incluir: cobrar duas vezes; vender estoque inexistente; permitir acesso ao pedido de outro cliente; perder o pedido depois do pagamento; calcular total incorreto; impedir uso por teclado; publicar uma versão que não inicia. Em um site institucional, os riscos podem ser outros: formulário não enviar; telefone incorreto; página principal indisponível; layout quebrar em celular; script de terceiros bloquear o carregamento. Os dois projetos precisam de testes, mas não do mesmo portfólio. Transforme risco em cenário verificável Use uma matriz simples: Falha Impacto Probabilidade Detectabilidade sem teste Prioridade Cobrança duplicada Crítico Média Baixa P1 Campo desalinhado Baixo Alta Alta P4 Acesso entre clientes Crítico Média Baixa P1 E mail não enviado Alto Média Média P2 Imagem secundária ausente Baixo Baixa Alta P4 A classificação não precisa ser matematicamente perfeita. Ela precisa orientar investimento. Para cada risco, registre: 1. condição inicial; 2. ação; 3. resultado esperado; 4. consequência se falhar; 5. menor camada capaz de detectar; 6. frequência de execução. A menor camada costuma produzir a resposta mais útil O capítulo sobre testes do livro Software Engineering at Google recomenda escrever o menor teste possível para determinada funcionalidade. Um teste pequeno costuma ser: rápido; determinístico; fácil de executar; fácil de diagnosticar; pouco dependente de infraestrutura. Isso não significa testar tudo como unidade. Significa evitar um navegador completo quando uma função pura detectaria a mesma falha. Quatro camadas principais Testes unitários Validam uma unidade pequena de comportamento. Exemplo: Adequados para: cálculos; validações; transições de estado; regras; formatação; transformação. Limitação: uma função correta não garante integração correta com banco, API ou interface. Testes de integração Validam componentes reais em conjunto. Exemplos: repositório com banco; endpoint com autenticação; aplicação com fila; serviço com armazenamento; migração de banco; geração e consumo de eventos. Teste de integração de API: A utilidade está em usar o máximo possível dos componentes que realmente serão executados. Testes de contrato Verificam compatibilidade entre produtor e consumidor. Podem validar: schema; campos obrigatórios; status; tipos; eventos; compatibilidade de OpenAPI; expectativas do consumidor. Eles detectam uma classe importante de falha: cada serviço funciona sozinho, mas não conversa mais com o outro. O artigo sobre API REST bem desenhada apresenta os elementos que compõem esse contrato. Testes ponta a ponta Executam um fluxo amplo como o usuário ou sistema consumidor. Exemplo: Esses testes oferecem confiança no fluxo, mas são: mais lentos; mais caros; dependentes de dados; mais sensíveis ao ambiente; mais difíceis de diagnosticar. Use os nos caminhos críticos, não para repetir todas as combinações já cobertas em camadas menores. Um risco, várias barreiras Risco: cobrança duplicada. Unidade A função gera a mesma chave para a mesma tentativa. Integração O banco impede duas operações confirmadas com a mesma chave. Contrato O gateway recebe e respeita a chave de idempotência. Ponta a ponta Duas submissões rápidas produzem somente um pagamento. Monitoramento Uma métrica alerta sobre duplicidade inesperada. Testes não precisam carregar toda a responsabilidade. Constraints, idempotência e observabilidade também protegem o sistema. Teste comportamento, não detalhes internos A Testing Library orienta escrever testes que se aproximem da maneira como o software é usado. Teste frágil: Teste orientado ao uso: O segundo verifica um resultado observável e ajuda a preservar semântica acessível. Evite testar: estado interno sem relevância externa; nome de método privado; estrutura incidental; classe CSS usada apenas para estilo; sequência exata de chamadas quando o resultado basta. Teste detalhes internos quando eles constituem um contrato importante, não apenas porque são fáceis de acessar. Dados de teste precisam de projeto Falhas comuns: todos os testes usam o mesmo usuário; a suíte depende da ordem; dados permanecem após falha; horários reais alteram resultado; IDs são fixos; ambientes compartilham banco; testes modificam produção por configuração incorreta. Princípios: isolamento; geração determinística; limpeza; relógio controlável; serviços externos simulados quando apropriado; dados mínimos; proibição técnica de apontar para produção. Exemplo: Endpoints de suporte a testes nunca devem ser expostos em produção. Mocks: use para controlar, não para imaginar Mocks são úteis quando: o serviço externo é caro; a falha precisa ser reproduzida; a resposta precisa ser determinística; a integração não pode ser chamada em cada teste; a unidade precisa ser isolada. Risco: o mock continua retornando o formato antigo enquanto o serviço real muda. Mitigue com: testes de contrato; sandbox; gravações controladas; integração periódica real; schemas compartilhados; validação de fixtures. Quanto mais distante do comportamento real, menor a confiança. Testes E2E estáveis não usam espera cega Evite: A espera fixa: deixa a suíte lenta; falha quando cinco segundos não bastam; desperdiça tempo quando a ação termina antes; esconde falta de sincronização. O Playwright executa verificações automáticas de acionabilidade antes de ações e oferece asserções que aguardam condições. Prefira: Isso aguarda o estado esperado até o limite configurado. Retry não corrige teste instável A documentação de retries do Playwright classifica testes como aprovados, instáveis ou falhos conforme o comportamento nas repetições. Um retry pode ajudar a: coletar diagnóstico; reduzir interrupção temporária; identificar flakiness. Não deve transformar falha recorrente em sucesso aceitável. Para cada teste instável: 1. preserve trace, vídeo, screenshot e log; 2. classifique a causa; 3. corrija sincronização ou isolamento; 4. coloque em quarentena quando necessário; 5. defina prazo; 6. não aumente retries indefinidamente. Uma suíte ignorada não oferece proteção. Acessibilidade exige automação e uso manual Automação detecta alguns problemas: rótulos ausentes; relações inválidas; certos contrastes; atributos incorretos. Não decide: se o texto alternativo é útil; se a ordem faz sentido; se o fluxo é compreensível; se o foco vai ao lugar correto; se a tarefa funciona com leitor de tela. Combine: análise automatizada; navegação por teclado; zoom; leitor de tela; revisão de conteúdo; tarefas reais. O checklist de acessibilidade web detalha essa combinação. Performance também pode regredir Testes podem impor limites: tamanho de bundle; quantidade de requisições; tempo de resposta de endpoint; consultas por operação; LCP de laboratório; duração de tarefa; memória. Exemplo de condição de pipeline: Métricas de laboratório não substituem dados reais. Use as como barreiras de regressão, em conjunto com o processo de performance web. Segurança precisa entrar em várias fases O OWASP Web Security Testing Guide cobre testes de configuração, identidade, autenticação, autorização, sessão, validação, criptografia, lógica de negócio e APIs. Uma estratégia pode incluir: Em cada mudança análise estática; testes de autorização; dependências; segredos; validação; autenticação. Periodicamente testes dinâmicos; revisão de configuração; análise de sessão; varredura autenticada; revisão de exposição. Antes de mudanças sensíveis modelagem de ameaças; revisão especializada; teste de abuso; avaliação manual. Scanner não comprova ausência de vulnerabilidade. O que executar em cada momento Durante o desenvolvimento unidade afetada; componente; integração local. Em cada pull request análise estática; unitários; integrações relevantes; contrato; acessibilidade automatizada; segurança básica. Na branch principal conjunto ampliado; build; migrações; E2E críticos; performance de laboratório. Antes do deploy artefato; configuração; smoke tests; backup e rollback; validação de ambiente. Depois do deploy healthcheck; smoke test em produção; métricas; erros; fluxo sintético seguro. O artigo sobre CI/CD seguro mostra como organizar essas etapas. Cobertura de código não mede valor do teste Cobertura informa quais trechos foram executados. Ela não comprova que: as asserções são úteis; os cenários importantes foram testados; regras estão corretas; segurança foi avaliada; integração funciona; requisitos foram compreendidos. Use cobertura para localizar áreas não exercitadas, não como objetivo isolado. Teste que executa uma linha sem verificar resultado melhora o percentual e não aumenta confiança. Estratégia mínima por tipo de projeto Site institucional build; links; formulários; navegação; acessibilidade; layout; metadados; performance; disponibilidade. Aplicação CRUD interna regras; permissões; integração com banco; migrações; API; fluxos críticos; auditoria. Comércio eletrônico preço; estoque; carrinho; cupom; pagamento; idempotência; pedidos; autorização; integrações; recuperação. API pública schema; compatibilidade; autenticação; autorização; rate limiting; paginação; idempotência; erros; documentação. Critério para adicionar um teste Adicione quando ele: protege uma regra importante; reproduz um defeito real; cobre uma fronteira; valida contrato; reduz risco de regressão; documenta comportamento difícil. Não adicione apenas para elevar um número. O portfólio saudável A forma exata varia. Uma aplicação centrada em banco pode exigir mais integração. Uma biblioteca pode depender mais de testes unitários e contrato. Um produto visual precisa de validação de interface. A estratégia correta é a que oferece evidência proporcional ao risco sem transformar a suíte em um segundo sistema impossível de manter.