
Testes como contrato: cobertura, determinismo e evidências no CI
Objetivos desta aula
- Escolher testes conforme risco e custo
- Definir limites de cobertura verificáveis
- Eliminar dependências de relógio e rede nos testes unitários
- Publicar evidências mesmo quando um teste falha
- Vincular aprovação de PR a checks obrigatórios
Teste automatizado é um contrato executável: para o CloudShop, calcular um total e recusar estoque insuficiente são comportamentos verificáveis. Antes de escrever YAML, descreva o resultado esperado e a regressão que cada caso deve impedir.
Camadas têm responsabilidades diferentes. Testes unitários isolam regras; integração verifica fronteiras reais, como persistência; testes ponta a ponta exercitam jornadas completas. Não replique toda combinação em E2E: reserve o custo maior para fluxos críticos.
Determinismo dá confiança. Um teste que depende da hora atual, da ordem de execução ou de uma API pública pode falhar sem alteração de produto. Injete relógio e cliente HTTP, controle os dados e restaure mocks após cada caso; retry não corrige a causa.
Cobertura é um sinal limitado. Executar uma linha não garante uma asserção útil; cobertura de branches mostra caminhos condicionais visitados, mas não prova correção. Use coverage.thresholds como limite mínimo e revise casos de erro, fronteiras e regras de negócio.
O comando precisa ser adequado ao CI. vitest run termina com um código de saída, enquanto o modo watch fica esperando alterações. O exemplo pressupõe vitest e @vitest/coverage-v8 em versões compatíveis já registrados no lockfile.
Falhar deve bloquear o caminho seguinte. Não use continue-on-error no teste obrigatório. Um job de build dependente deve declarar needs no job de testes; o processo de merge também precisa de proteção de branch exigindo esse check.
Evidências precisam sobreviver à falha. Publique coverage/ com if: always() para investigar regressões mesmo quando o limite de cobertura reprova. Defina retenção curta e não coloque respostas reais de clientes ou tokens dentro dos relatórios.
Maturidade é medida ao longo do tempo. Acompanhe duração e taxa de testes instáveis, priorize os que bloqueiam o time e inclua novos casos para bugs corrigidos. Um pipeline verde só tem valor quando o conjunto em vitest run representa riscos relevantes.
Na prática
vitest.config.ts: limite mínimo de cobertura
typescript
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
environment: "node", // Regras da API não precisam de navegador.
clearMocks: true,
coverage: {
provider: "v8",
include: ["src/**/*.ts"], // Inclui também código não importado pelos testes.
exclude: ["src/**/*.test.ts", "src/**/*.d.ts"],
reporter: ["text", "html", "lcov"],
thresholds: { lines: 80, functions: 80, statements: 80, branches: 75 },
},
},
});.github/workflows/testes.yml: execução e evidências
yaml
name: testes
on: [pull_request, push]
permissions:
contents: read # Testes não precisam escrever no repositório.
jobs:
unitarios:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npx --no-install vitest run --coverage
- uses: actions/upload-artifact@v4
if: always() # Preserve o relatório mesmo quando o teste reprovar.
with:
name: cobertura-unitarios
path: coverage/
retention-days: 7
if-no-files-found: warnPor que isso importa
Testes previsíveis e evidências acessíveis reduzem regressões sem transformar cada falha de CI em investigação manual demorada.
Erro comum
Confundir alta cobertura com boa qualidade ou repetir um teste instável até ele ficar verde.
Dica de produção
Exija o check de testes nas regras de proteção de branch e revise os limites de cobertura junto com o risco do produto.
Alerta de segurança
Relatórios e fixtures também podem vazar informações: use dados sintéticos e não execute PRs não confiáveis com secrets de produção.
Pergunta de entrevista
Um projeto tem 95% de cobertura e ainda sofre regressões: o que você investigaria além da porcentagem?
Glossário
- asserção
- Verificação explícita de que o resultado observado corresponde ao esperado.
- teste determinístico
- Teste que produz o mesmo resultado sob entradas e ambiente controlados.
- branch coverage
- Medida dos caminhos condicionais exercitados pelos testes.
- flaky test
- Teste que alterna entre sucesso e falha sem mudança relevante no produto.
- check obrigatório
- Resultado de CI que uma regra do repositório exige antes do merge.
Conexão com o CloudShop
Adicionar limites de cobertura às regras de pedidos do CloudShop e publicar relatórios de testes em cada PR.
Quiz da aula
1. Por que usar vitest run no CI?
2. O que alta cobertura não garante?
3. Como preservar relatórios de uma execução reprovada?
Minhas anotações
Salvo automaticamente neste navegador.
