Módulo 13 - Testes avançados
parametrize e testar exceções
10 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 01/07/2026
O que você vai aprender
- Usar @pytest.mark.parametrize para rodar um teste com várias entradas.
- Cobrir casos de borda sem copiar funções de teste.
- Verificar exceções com pytest.raises.
- Checar a mensagem da exceção junto com o tipo.
Ouvir o resumo desta aula
Um recap de cerca de 2 minutos na voz do Valim, para ouvir no trânsito ou na academia.
Ler a transcrição do resumo
Resumo da aula: parametrize e testar exceções.
Os objetivos desta aula. Usar @pytest.mark.parametrize para rodar um teste com várias entradas. Cobrir casos de borda sem copiar funções de teste. Verificar exceções com pytest.raises. Checar a mensagem da exceção junto com o tipo.
Veja o essencial, parte por parte.
Um teste, muitos casos. @pytest.mark.parametrize roda o mesmo teste com várias entradas e resultados esperados.
Testar que o erro certo acontece. Testar o caminho de sucesso é metade do trabalho.
Cobrir os casos de borda. Reunindo os dois recursos, você consegue cobrir com poucos linhas o que importa numa função: os valores típicos, os limites e os inválidos.
Esse foi o resumo do essencial. Para se aprofundar, leia a aula completa e responda os exercícios.
Um teste, muitos casos
Imagine testar uma função que verifica se um número é par. Você quer conferir vários casos: pares, ímpares, zero, negativos. Escrever uma função de teste para cada seria repetitivo, e a repetição é inimiga da manutenção. O parametrize resolve isso com elegância. Você escreve o teste uma vez e fornece uma lista de entradas com os resultados esperados. O pytest roda a função uma vez para cada conjunto, e cada um aparece no relatório como um caso separado, com seus próprios valores.
import pytest
def eh_par(n):
return n % 2 == 0
@pytest.mark.parametrize("entrada, esperado", [
(2, True),
(3, False),
(0, True),
(-4, True),
(-7, False),
])
def test_eh_par(entrada, esperado):
assert eh_par(entrada) == esperadoCinco casos, uma função. Cada tupla vira um teste independente no relatório.
Os ganhos são concretos. Se um caso falha, o pytest diz exatamente qual conjunto de dados quebrou, sem confusão. Acrescentar um novo caso é adicionar uma linha à lista, não copiar uma função inteira. E a intenção fica cristalina: a tabela de entradas e saídas esperadas funciona quase como uma documentação do comportamento da função. Esse é o padrão certo sempre que você percebe que está prestes a copiar e colar um teste só mudando os números.
Testar que o erro certo acontece
Testar o caminho de sucesso é metade do trabalho. Um código robusto também levanta erros de propósito quando recebe algo inválido, e isso precisa ser testado. Não faz sentido deixar a exceção explodir e derrubar o teste; você quer justamente afirmar que ela aconteceu. Para isso existe o pytest.raises, usado com with. Você coloca dentro do bloco a chamada que deveria falhar e diz qual exceção espera. Se ela ocorre, o teste passa; se não, o teste falha, porque o erro esperado não veio.
import pytest
def raiz_quadrada(x):
if x < 0:
raise ValueError("nao existe raiz real de numero negativo")
return x ** 0.5
def test_raiz_de_numero_valido():
assert raiz_quadrada(9) == 3.0
def test_raiz_de_negativo_levanta():
with pytest.raises(ValueError):
raiz_quadrada(-1)
def test_raiz_de_negativo_mensagem():
# match verifica um trecho da mensagem, alem do tipo.
with pytest.raises(ValueError, match="numero negativo"):
raiz_quadrada(-4)with pytest.raises afirma que a exceção acontece; match confere a mensagem.
O parâmetro match, no último teste, acrescenta rigor. Ele verifica que a mensagem da exceção contém o trecho indicado, além de checar o tipo. Isso protege contra um engano sutil: o código levantar a exceção certa pelo motivo errado. Testar a mensagem confirma que a falha é aquela que você esperava. Junto com o parametrize, o pytest.raises fecha o ciclo de cobertura: você testa o que deve funcionar e também o que deve falhar, que é onde muitos bugs se escondem.
Cobrir os casos de borda
Reunindo os dois recursos, você consegue cobrir com poucos linhas o que importa numa função: os valores típicos, os limites e os inválidos. Casos de borda são onde os defeitos moram, o zero, o vazio, o negativo, o valor máximo, e o parametrize deixa listá-los sem esforço. As entradas inválidas, que devem levantar erro, entram com pytest.raises. Uma função bem testada tem essas três frentes cobertas, e o relatório verde passa a significar algo de verdade.
| Frente | Ferramenta | Exemplo |
|---|---|---|
| Casos típicos | parametrize | somar(2, 3) == 5 |
| Casos de borda | parametrize | somar(0, 0), valores negativos, máximos |
| Entradas inválidas | pytest.raises | dividir(1, 0) levanta ZeroDivisionError |
Três frentes de teste que juntas dão confiança real numa função.
Um lembrete de bom senso: cobrir não é testar toda combinação imaginável, é escolher os casos que representam classes de comportamento. Para uma faixa de 0 a 100, você não testa os 101 valores; testa um valor no meio, os extremos 0 e 100, e o que fica logo fora da faixa para conferir o erro. Poucos casos bem escolhidos cobrem muito. Essa mentalidade, aliada ao parametrize e ao pytest.raises, produz suítes enxutas que ainda assim pegam o que precisa ser pego.
Teste rápido
Como você testa que uma função levanta ValueError para uma entrada inválida?
Perguntas frequentes
- Cada conjunto do parametrize é um teste separado?
- Sim. O pytest executa a função de teste uma vez para cada conjunto de dados e trata cada execução como um caso independente. No relatório, eles aparecem separados, então você sabe exatamente qual entrada falhou, sem ambiguidade. Adicionar um caso é só incluir mais uma linha na lista.
- Por que não usar um for dentro do teste em vez de parametrize?
- Um for pararia no primeiro assert que falhasse e não diria qual iteração quebrou com clareza. Com parametrize, cada caso roda de forma isolada, todos são reportados e a falha aponta a entrada exata. O relatório fica muito mais informativo do que um laço manual.
- pytest.raises captura a exceção como um except comum?
- Ele funciona como um bloco que espera a exceção. Se a exceção indicada ocorre dentro do with, o teste segue e passa; se não ocorre, o teste falha. Você pode inspecionar a exceção capturada pelo atributo value do objeto retornado, útil para checar detalhes além do tipo.
- Para que serve o parâmetro match do pytest.raises?
- Para verificar que a mensagem da exceção contém um trecho esperado, além do tipo. Isso evita passar um teste por acaso quando o código levanta a exceção certa pelo motivo errado. É uma checagem a mais de que a falha é exatamente aquela que você quis provocar.
- Quantos casos de borda devo testar?
- O suficiente para representar as classes de comportamento, não toda combinação possível. Para uma faixa, teste um valor típico, os limites e um valor logo fora dela. Poucos casos bem escolhidos cobrem a maior parte dos defeitos, mantendo a suíte enxuta e rápida.
Fontes
Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.