Cobertura responde quais linhas e caminhos foram executados pela suíte. Ela encontra pontos esquecidos, mas não mede a qualidade das asserções nem prova ausência de defeitos.
Medir linhas e branches
python -m pip install coverage pytest
coverage run --branch -m pytest
coverage report -m
coverage html
Abra htmlcov/index.html e examine linhas ausentes. Branch coverage revela decisões nas quais apenas um destino foi exercitado, algo que a cobertura de linhas pode esconder.
Centralize opções em .coveragerc:
[run]
branch = True
source = src
[report]
show_missing = True
fail_under = 85
O limite deve impedir queda acidental, não incentivar testes sem valor. Exclua código somente quando houver justificativa verificável. O guia de pytest mostra como escrever cenários, e o artigo sobre fixtures e mocks ajuda a isolar dependências.
Interpretar o relatório
Priorize regras de negócio, tratamento de erros e fronteiras externas. Uma linha trivial coberta pesa igual a uma decisão financeira no percentual, mas não no risco. Revise também testes que executam o código sem afirmar o resultado.
Na CI, gere um formato legível pela plataforma e falhe abaixo do limite acordado. Não publique relatórios com caminhos, variáveis ou artefatos sensíveis.
A documentação oficial do coverage.py, consultada em 22 de julho de 2026, detalha cobertura de statements, branches e formatos de relatório. Use o número como mapa de investigação, não como objetivo isolado.
Entender o ciclo medir, combinar e relatar
coverage.py separa a execução do código da apresentação dos resultados. coverage run coleta dados e grava o arquivo .coverage; coverage report produz um resumo no terminal; coverage html cria uma navegação detalhada; coverage xml e coverage json atendem integrações automatizadas. Essa separação permite gerar vários relatórios sem repetir toda a suíte.
Sempre execute a medição a partir de um diretório previsível. Se partes da suíte rodam em processos ou tarefas diferentes, cada execução pode gerar dados próprios, que devem ser combinados antes do relatório final:
coverage erase
coverage run --parallel-mode -m pytest tests/unit
coverage run --parallel-mode -m pytest tests/integration
coverage combine
coverage report -m
coverage erase evita misturar o resultado atual com dados antigos. O modo paralelo cria arquivos distintos e coverage combine os reúne. Em CI distribuída, baixe os artefatos de todas as tarefas para um diretório comum antes de combinar. Só compare porcentagens produzidas com a mesma configuração e o mesmo conjunto de arquivos.
Preferir branch coverage para decisões
Cobertura de linhas registra se uma linha foi executada, mas pode esconder um caminho ausente. Considere:
def calcular_frete(total: float, expresso: bool) -> float:
if total >= 200 or expresso:
return 0
return 18
Um teste com total=250 executa o retorno gratuito, mas não demonstra que expresso=True funciona com um total menor. Outro teste precisa exercitar o retorno pago. Branch coverage observa as transições possíveis de uma decisão e indica caminhos parciais no relatório HTML.
Isso não significa criar um teste para cada combinação mecânica. Escolha casos que representem comportamentos: limite abaixo de 200, exatamente 200, entrega expressa e entrada inválida quando aplicável. As asserções devem conferir o valor devolvido e efeitos relevantes, não apenas chamar a função.
Configurar o escopo corretamente
O argumento source faz coverage.py acompanhar também módulos que poderiam ter sido executados, o que ajuda a listar arquivos totalmente esquecidos. Ajuste o caminho ao layout real:
[run]
branch = True
source =
src
omit =
*/tests/*
*/migrations/*
[report]
show_missing = True
skip_covered = False
precision = 1
fail_under = 85
[html]
directory = htmlcov
Não copie exclusões sem analisar o projeto. Migrações geradas podem ser excluídas, enquanto uma migração escrita à mão e com transformação crítica talvez mereça teste. Arquivos de teste costumam ficar fora da métrica do código de produção, mas helpers complexos usados pela suíte podem exigir verificação própria.
O contexto de execução também importa. Rodar a suíte a partir de diretórios diferentes pode produzir caminhos que não combinam. Padronize o comando local e o da CI e mantenha .coveragerc, pyproject.toml ou setup.cfg versionado como fonte única da configuração.
Usar exclusões com parcimônia
Algumas linhas são defensivas ou específicas de plataforma. coverage.py reconhece comentários como # pragma: no cover, mas a exceção deve ser revisável:
if TYPE_CHECKING:
from pacote_externo import Cliente
if __name__ == "__main__": # pragma: no cover
main()
Antes de excluir, pergunte se o comportamento pode ser testado por uma interface pública. Não marque blocos difíceis apenas para melhorar o painel. Uma exclusão ampla reduz a capacidade do relatório de revelar riscos futuros. Regras de exclusão por expressão regular também precisam ser específicas e documentadas.
Definir uma política de limite útil
Não existe porcentagem universal. Um projeto novo pode começar com um limite elevado; uma base antiga talvez precise registrar o valor atual e impedir queda enquanto amplia áreas críticas. O fail_under global é simples, porém não impede que código novo sem testes seja compensado por módulos antigos bem cobertos.
Em revisões, observe o diff e pergunte quais caminhos novos foram introduzidos. Uma função de autenticação com 90% de cobertura pode ser mais arriscada do que um módulo de formatação com 60%. Combine o limite automático com revisão de cenários, testes de regressão para defeitos encontrados e análise das linhas ausentes.
Evite arredondamento surpreendente. precision muda a exibição, e o limite usa o valor medido. Defina ambos conscientemente e execute o mesmo comando que a CI antes de enviar uma alteração.
Integrar com pytest e subprocessos
coverage.py pode iniciar pytest diretamente com coverage run -m pytest, o que mantém a ferramenta de medição explícita. O plugin pytest-cov oferece opções integradas ao pytest, mas não é obrigatório. Escolha uma abordagem e documente o comando oficial para que a equipe não gere números diferentes.
Código executado em subprocessos exige configuração adicional, pois um novo interpretador não herda automaticamente a medição. Consulte o suporte de subprocessos da versão usada e confirme que os arquivos paralelos foram salvos e combinados. Não presuma que o processo pai representa workers, filas ou comandos invocados externamente.
Ler o relatório como ferramenta de diagnóstico
Comece pelas linhas ausentes e parciais em módulos de maior risco. Em tratamento de erros, verifique falha de rede, dados inválidos, permissões e limpeza de recursos. Em loops, teste coleções vazias e interrupções. Em condições, procure operandos curtos que impeçam a avaliação de parte da expressão.
Uma melhoria real de cobertura deve vir acompanhada de uma asserção capaz de falhar quando o comportamento quebra. Para avaliar isso, altere mentalmente ou temporariamente o resultado esperado: o teste detectaria a regressão? Técnicas como mutation testing podem aprofundar essa análise, mas não substituem a leitura dos casos.
Na CI, publique o resumo necessário para revisão e restrinja o acesso ao HTML quando o código não for público. Não inclua arquivos de configuração com segredos nem faça upload indiscriminado do diretório de trabalho. O artefato útil é o relatório, não todo o ambiente de execução.