
Passo 1 de 8
Transformar o contrato em cenários
Identifique comportamentos verificáveis diretamente no contrato público de uma operação, sem consultar sua implementação nem acrescentar requisitos.
Trilha de aprendizado · Nível 8 · Tutorial 2
Derivar casos de sucesso, limites e falhas a partir do comportamento esperado de uma operação, verificando também as exceções que ela deve produzir.
Transformar o contrato em cenários
Identifique comportamentos verificáveis diretamente no contrato público de uma operação, sem consultar sua implementação nem acrescentar requisitos. 2 min
Escolher entradas representativas
Agrupe entradas pelo comportamento esperado e escolha casos que verifiquem regras distintas sem repetição desnecessária. 2 min
Explorar os valores de fronteira
Selecione os limites inclusivos e seus vizinhos imediatos para detectar erros de inclusão ou exclusão na faixa válida. 2 min
Distinguir vazio, unitário e ausente
Reconheça diferenças estruturais entre ausência, coleção vazia e listas com diferentes quantidades de elementos, escolhendo casos coerentes com o contrato. 2 min
Definir expectativas independentes do código
Transforme cenários de sucesso em testes legíveis, usando resultados literais derivados do contrato da operação. 2 min
Exigir a exceção esperada com pytest.raises
Use pytest.raises para fazer um teste passar somente quando a operação produzir o tipo de exceção previsto no contrato. 3 min
Verificar o contexto da exceção
Capture a exceção produzida e verifique os atributos públicos que explicam a falha, sem depender de detalhes irrelevantes da mensagem. 2 min
Aplicar e revisar a seleção de testes
Revise uma seleção de casos, complete uma pequena suíte local e justifique as verificações acrescentadas. 4 min

Passo 1 de 8
Identifique comportamentos verificáveis diretamente no contrato público de uma operação, sem consultar sua implementação nem acrescentar requisitos.
Antes de escolher entradas ou consultar a implementação, leia o contrato público da operação. Ele informa quais entradas são aceitas, qual resultado é prometido e quais falhas são esperadas.
Cada regra explícita pode ser convertida em um cenário verificável. Já uma preferência pessoal ou uma possibilidade não documentada não deve virar exigência do teste.
Exemplo
A função calcular_media é pura: recebe uma lista não vazia de pontuações inteiras entre 0 e 100, com os dois limites aceitos, e devolve a média.
Rejeições documentadas:
ValueError;None → TypeError;PontuacaoInvalida, com os atributos públicos valor, minimo e maximo.Dica
Neste momento, registre os comportamentos que precisam ser verificados. A escolha das entradas representativas será feita nos próximos steps.
Uma matriz de cenários liga três elementos: a regra pública, a condição da entrada e o comportamento esperado. Para o caso-guia, ela deve incluir o cálculo bem-sucedido e cada forma de rejeição documentada.
Não acrescente, por exemplo, uma regra de arredondamento ou uma ordem específica entre validações se o contrato não garante esses comportamentos.
O contrato é a origem comum dos cenários de sucesso e de falha. Cada ramificação representa uma promessa pública diferente, não um caminho interno do código.

Uma regra documentada sustenta cada cenário; suposições ficam fora da matriz.
Exemplo
ValueError.None → produz TypeError.PontuacaoInvalida com contexto público.“Devolve sempre duas casas decimais” não entra na matriz, pois essa promessa não aparece no contrato.
Associe cada condição de entrada ao comportamento público esperado.
Toque em um item e depois no par correspondente.
Como a função calcula uma média, o teste deve exigir duas casas decimais mesmo que o contrato não mencione formatação ou arredondamento.

Passo 2 de 8
Agrupe entradas pelo comportamento esperado e escolha casos que verifiquem regras distintas sem repetição desnecessária.
Uma partição de equivalência reúne entradas que devem seguir a mesma regra do contrato. No caso da média, uma separação inicial é:
Ao investigar uma partição, mantenha as demais condições válidas. Assim, fica claro qual regra o caso realmente verifica.
Cada grupo reúne várias entradas possíveis, mas apenas alguns representantes precisam entrar na suíte.

Primeiro agrupe pelo comportamento esperado; depois escolha um representante relevante de cada grupo.
Um representante é escolhido pela regra pública que exercita, não por caminhos internos imaginados no código. Por exemplo, [20, 80] pode representar entradas válidas, [-10, 50] a rejeição por valor abaixo da faixa e [50, 120] a rejeição por valor acima da faixa.
Entradas válidas pertencem à mesma partição de aceitação, mas não precisam produzir a mesma média. “Comportamento semelhante” significa seguir a mesma regra geral, e não retornar sempre o mesmo valor.
Exemplo
Se a suíte já verifica [20, 80] e inclui [30, 70] apenas para confirmar novamente uma lista válida com média 50, um dos casos pode ser redundante. Mantenha ambos somente se cada um demonstrar uma regra pública diferente. A quantidade de caminhos internos percorridos não é uma justificativa baseada no contrato.
Dica
Complete: “Este caso permanece na suíte porque demonstra que…”. Se a resposta repetir exatamente a justificativa de outro caso, verifique se um deles pode ser retirado.
Relacione cada lista à partição de equivalência pertinente.
Toque em um item e depois no par correspondente.
Considere a seleção [20, 80], [30, 70], [-10, 50] e [50, 120]. Retire um caso redundante e justifique por que as três partições continuam representadas.
Escreva pelo menos 60 caracteres (0/60).

Passo 3 de 8
Selecione os limites inclusivos e seus vizinhos imediatos para detectar erros de inclusão ou exclusão na faixa válida.
Uma fronteira é um ponto em que o comportamento esperado pode mudar. No contrato do caso-guia, pontuações de 0 a 100 são válidas, inclusive.
Como o domínio é formado por inteiros, os vizinhos imediatos do limite inferior são -1, 0 e 1. No limite superior, são 99, 100 e 101.
Esses valores ajudam a revelar erros como rejeitar acidentalmente o próprio limite ou aceitar um valor logo fora da faixa.
A região central representa a faixa aceita. Os pontos imediatamente externos devem seguir o comportamento de rejeição.

Em cada extremidade, verifique o vizinho externo, o limite e o vizinho interno.
Exemplo
Mantenha a outra pontuação válida e varie somente o valor próximo à fronteira:
[20, -1] → PontuacaoInvalida[20, 0] → média 10[20, 1] → média 10.5[20, 99] → média 59.5[20, 100] → média 60[20, 101] → PontuacaoInvalidaOs resultados literais vêm da regra pública da média. Os casos externos seguem a regra pública de rejeição.
Dica
Um representante comum, como 50, confirma o comportamento geral da faixa válida, mas não demonstra que 0 e 100 são aceitos. Os casos de fronteira têm uma justificativa adicional: verificar exatamente onde o comportamento muda.
Qual conjunto verifica completamente as vizinhanças dos limites inclusivos de 0 e 100?
Considere novamente [20, valor], usando valor igual a -1, 0, 1, 99, 100 e 101. Explique quais entradas devem retornar uma média e quais devem produzir PontuacaoInvalida. Relacione sua resposta aos limites inclusivos.
Escreva pelo menos 60 caracteres (0/60).

Passo 4 de 8
Reconheça diferenças estruturais entre ausência, coleção vazia e listas com diferentes quantidades de elementos, escolhendo casos coerentes com o contrato.
No caso-guia, None, [], [0] e uma lista com vários elementos representam situações diferentes:
None: não há uma lista.[]: há uma lista, mas ela está vazia.[0]: há uma lista com um elemento, e zero é uma pontuação válida.[20, 40, 60]: há uma lista com vários elementos válidos.A quantidade de elementos pode mudar o comportamento esperado, mas somente o contrato determina se cada situação deve produzir um resultado ou uma exceção.

Da esquerda para a direita: ausência (None), lista vazia ([]), lista com o valor zero ([0]) e lista com vários valores.
Exemplo
Para a operação de média deste tutorial, a matriz pode conter:
| Entrada | Situação | Comportamento esperado |
|---|---|---|
| None | valor ausente | TypeError |
| [] | lista vazia | ValueError |
| [0] | lista unitária válida | resultado 0 |
| [20, 40, 60] | vários valores válidos | resultado 40 |
Essas expectativas vêm das regras públicas da operação. Em outra função, uma coleção vazia ou None poderia ter um significado diferente.
Dica
Não transforme uma convenção comum em requisito. Antes de esperar uma exceção para [] ou None, confirme que o contrato realmente define esse comportamento.
Ao investigar a quantidade de elementos, mantenha as pontuações válidas. Assim, [40] representa claramente uma lista unitária, enquanto [20, 40, 60] representa uma lista com vários elementos.
Uma entrada como [101] mistura duas características: é unitária e contém uma pontuação fora da faixa. Se ela for rejeitada, o cenário demonstra a regra da faixa, não o funcionamento normal de uma lista unitária.
Exemplo
Para distinguir estruturas, uma seleção enxuta pode usar [], [0] e [20, 40, 60], além de None para representar ausência. Cada caso acrescenta uma situação pública diferente.
Adicionar [40] pode ser redundante se [0] já demonstrar adequadamente a lista unitária. Ele só se justifica se houver outra regra específica que você queira evidenciar.
Atenção
Evite entradas que reúnam várias condições inválidas, como uma coleção com diferentes valores fora da faixa, quando a ordem das validações não faz parte do contrato. O resultado pode depender de qual problema a implementação encontra primeiro, sem revelar uma regra pública relevante.
Considere estas entradas: None, [], [0], [40], [20, 40, 60], [101] e [101, -1].
Escolha apenas os casos necessários para distinguir ausência, vazio, lista unitária válida e lista com vários elementos válidos. Para cada escolha, informe o comportamento esperado e justifique qual regra ela demonstra. Aponte também quais casos você descartaria por redundância ou por misturarem outra condição.
Escreva pelo menos 80 caracteres (0/80).

Passo 5 de 8
Transforme cenários de sucesso em testes legíveis, usando resultados literais derivados do contrato da operação.
Em um bom teste, o resultado esperado vem da regra pública da operação — não da forma como ela foi implementada.
Para a entrada [20, 40, 60], a regra da média permite estabelecer diretamente o resultado literal 40.0. Dados pequenos tornam essa conferência simples.
Evite repetir no teste o cálculo feito pela implementação. Se o mesmo erro estiver nos dois lugares, o teste poderá passar sem revelar o defeito.
O caminho seguro deriva a expectativa do contrato e mantém o teste independente do código testado.

À esquerda, a regra produz um resultado literal usado pelo teste. À direita, o teste espelha a implementação e pode repetir o mesmo defeito.
Exemplo
Prefira assert calcular_media([20, 40, 60]) == 40.0.
Evite calcular a expectativa com outro laço, com sum(valores) / len(valores) ou chamando novamente calcular_media. O teste deve declarar o comportamento esperado, não reconstruir o algoritmo.
Em uma pasta de projeto no seu computador, crie pontuacoes.py com o conteúdo completo abaixo. A exceção de domínio também fica nesse módulo. Neste step, a prática se concentra apenas nos cenários de sucesso.
Operação completa usada na prática local.
class PontuacaoInvalida(Exception):
def __init__(self, valor: int, minimo: int, maximo: int):
self.valor = valor
self.minimo = minimo
self.maximo = maximo
super().__init__(
f"Pontuação {valor} fora da faixa de {minimo} a {maximo}"
)
def calcular_media(pontuacoes: list[int]) -> float:
"""Calcula a média de uma lista não vazia de pontuações de 0 a 100."""
if pontuacoes is None:
raise TypeError("pontuacoes não pode ser None")
if not pontuacoes:
raise ValueError("pontuacoes não pode ser vazia")
for pontuacao in pontuacoes:
if pontuacao < 0 or pontuacao > 100:
raise PontuacaoInvalida(pontuacao, 0, 100)
return sum(pontuacoes) / len(pontuacoes)Crie a pasta tests e, dentro dela, o arquivo test_pontuacoes.py. Cada nome descreve a condição e o comportamento esperado. As verificações de uma mesma função podem ser complementares, desde que demonstrem o mesmo cenário.
Testes-base com expectativas literais derivadas da regra.
from pontuacoes import calcular_media
def test_calcula_media_de_varias_pontuacoes_validas():
resultado = calcular_media([20, 40, 60])
assert resultado == 40.0
def test_devolve_a_propria_pontuacao_para_lista_unitaria():
resultado = calcular_media([75])
assert resultado == 75.0
Dica
Rode python -m pytest na pasta que contém pontuacoes.py e tests. Os valores 40.0 e 75.0 foram definidos diretamente a partir do contrato, antes de depender do cálculo interno da função.
Qual verificação testa a média de [0, 100] com uma expectativa independente da implementação?
Escreva uma função de teste para a entrada válida [0, 100]. Use um nome descritivo e uma expectativa literal derivada da regra.
Escreva pelo menos 60 caracteres (0/60).

Passo 6 de 8
Use pytest.raises para fazer um teste passar somente quando a operação produzir o tipo de exceção previsto no contrato.
Para testar uma entrada inválida, envolva a chamada com pytest.raises e informe a exceção prevista. O teste passa quando a chamada levanta esse tipo ou uma subclasse dele.
Prefira sempre o tipo específico do contrato. Usar Exception é amplo demais: falhas diferentes, inclusive defeitos inesperados, poderiam ser aceitas pelo teste.
Neste cenário, uma lista vazia deve produzir ValueError.
import pytest
from notas import calcular_media
def test_rejeita_lista_vazia():
with pytest.raises(ValueError):
calcular_media([])O resultado da chamada determina se a exigência foi atendida.

Somente uma exceção compatível com o tipo informado satisfaz pytest.raises.
Faça a preparação antes do with e deixe dentro dele apenas a chamada que deve falhar. Assim, uma exceção ocorrida durante a preparação não será confundida com o comportamento que o teste pretende verificar.
Quando a exceção esperada ocorre, o pytest encerra o bloco e o teste continua depois dele. Linhas colocadas após a chamada dentro do bloco não são executadas.
O bloco destaca exatamente qual operação deve levantar PontuacaoInvalida.
import pytest
from notas import PontuacaoInvalida, calcular_media
def test_rejeita_pontuacao_acima_do_maximo():
pontuacoes = [50, 101] # preparação fora do bloco
with pytest.raises(PontuacaoInvalida):
calcular_media(pontuacoes) # única chamada que deve falhar
# A execução do teste continua a partir daqui.Dica
Não coloque um assert depois da chamada que levanta a exceção, ainda dentro do with: essa linha nunca será alcançada. Verificações posteriores pertencem depois do bloco.
Três testes usam with pytest.raises(ValueError). No primeiro, a chamada levanta ValueError; no segundo, não levanta exceção; no terceiro, levanta TypeError. Qual alternativa descreve os resultados?
Complete o teste:
with pytest.raises(_____): calcular_media([101])

Passo 7 de 8
Capture a exceção produzida e verifique os atributos públicos que explicam a falha, sem depender de detalhes irrelevantes da mensagem.
pytest.raises(PontuacaoInvalida) verifica o tipo da falha. Quando o contrato também garante dados sobre ela, use as exc_info para capturar as informações da exceção.
Depois que o bloco with termina, exc_info.value fornece a instância que foi levantada. Nela, você pode consultar os atributos públicos previstos pelo contrato, como valor, minimo e maximo.
O objeto de captura e a exceção não são a mesma coisa: primeiro acesse exc_info.value; depois, consulte os atributos da instância.

A captura leva à instância da exceção; os atributos públicos ficam nessa instância.
As verificações ficam depois do bloco porque a chamada dentro dele interrompe o fluxo ao levantar a exceção.
import pytest
from pontuacoes import PontuacaoInvalida, calcular_media
def test_rejeita_pontuacao_acima_do_maximo_com_contexto():
with pytest.raises(PontuacaoInvalida) as exc_info:
calcular_media([40, 101])
erro = exc_info.value
assert erro.valor == 101
assert erro.minimo == 0
assert erro.maximo == 100
Exemplo
O pytest.raises demonstra que ocorreu PontuacaoInvalida. Já os três asserts demonstram que a exceção identifica o valor rejeitado e os limites inclusivos do contrato.
Nem toda situação exige conferir todos os atributos. Se um teste precisa demonstrar apenas qual entrada foi rejeitada, assert erro.valor == 101 pode ser suficiente.
Dica
Não compare a mensagem completa se seu texto não fizer parte do contrato público. Uma alteração de pontuação ou redação poderia quebrar o teste sem mudar o comportamento relevante. Prefira atributos públicos estáveis que representem o contexto da falha.
Ordene as ações de um teste que verifica o contexto de uma pontuação acima do máximo.

Passo 8 de 8
Revise uma seleção de casos, complete uma pequena suíte local e justifique as verificações acrescentadas.
Considere esta síntese do contrato de calcular_media:
[20, 40] → 30;[100] → 100;ValueError;None: TypeError;[101] → PontuacaoInvalida.Uma seleção proposta também contém [40, 60] → 50. Esse caso repete a regra das listas válidas comuns, enquanto o limite inferior 0 ainda não está representado. Além disso, a falha abaixo do mínimo pode verificar o contexto público da exceção: valor, minimo e maximo.

As fronteiras 0 e 100 pertencem à faixa válida; seus vizinhos externos pertencem a partições de falha.
Crie uma pasta para a prática com os arquivos media.py e tests/test_media.py. Os códigos abaixo são completos e podem ser copiados para esses caminhos.
Operação e exceção de domínio usadas na prática.
class PontuacaoInvalida(ValueError):
def __init__(self, valor: int, minimo: int, maximo: int):
self.valor = valor
self.minimo = minimo
self.maximo = maximo
super().__init__(
f"Pontuação {valor} fora da faixa de {minimo} a {maximo}"
)
def calcular_media(pontuacoes: list[int]) -> float:
"""Calcula a média de uma lista não vazia de pontuações de 0 a 100."""
if pontuacoes is None:
raise TypeError("pontuacoes não pode ser None")
if not pontuacoes:
raise ValueError("a lista de pontuações não pode estar vazia")
for valor in pontuacoes:
if valor < 0 or valor > 100:
raise PontuacaoInvalida(valor, 0, 100)
return sum(pontuacoes) / len(pontuacoes)
Suíte-base que será revisada e complementada.
import pytest
from media import PontuacaoInvalida, calcular_media
def test_calcula_media_de_pontuacoes_validas():
assert calcular_media([20, 40]) == 30
def test_calcula_media_de_outra_lista_valida():
assert calcular_media([40, 60]) == 50
def test_aceita_lista_unitaria_no_limite_superior():
assert calcular_media([100]) == 100
def test_rejeita_lista_vazia():
with pytest.raises(ValueError):
calcular_media([])
def test_rejeita_ausencia_de_lista():
with pytest.raises(TypeError):
calcular_media(None)
def test_rejeita_pontuacao_acima_do_maximo():
with pytest.raises(PontuacaoInvalida):
calcular_media([101])
Dica
No terminal, a partir da pasta que contém media.py, execute python -m pytest. Antes de alterar a suíte, confirme que os seis testes-base passam.
0 e compare o resultado com o literal esperado.[-1] que exija PontuacaoInvalida e, depois do bloco with, verifique valor == -1, minimo == 0 e maximo == 100 por meio de exc_info.value.python -m pytest.Mantenha somente a chamada que deve falhar dentro do bloco with pytest.raises.
Qual foi o resultado observado na sua execução? Explique qual caso você removeu, quais dois casos acrescentou e qual regra cada alteração demonstra.
Escreva pelo menos 80 caracteres (0/80).
Após remover test_calcula_media_de_outra_lista_valida, estes são os dois testes que completam a seleção:
def test_aceita_limite_inferior():
assert calcular_media([0]) == 0
def test_informa_contexto_da_pontuacao_abaixo_do_minimo():
with pytest.raises(PontuacaoInvalida) as exc_info:
calcular_media([-1])
erro = exc_info.value
assert erro.valor == -1
assert erro.minimo == 0
assert erro.maximo == 100
Resumo
Use esta revisão em novas seleções de testes.
Exception não substitui o tipo definido pelo contrato.Parabéns! Você concluiu: Selecionar casos de teste e verificar exceções
100 XP
Milhares de cursos online em vídeo, ebooks e áudiobooks.
Para testar seus conhecimentos no decorrer dos cursos online
Gerado diretamente na galeria de fotos do seu celular e enviado ao seu e-mail
Baixe nosso aplicativo pelo QR Code ou pelos links abaixo:.
+ de 10 milhões
de alunos
Certificado grátis e
válido em todo o Brasil
60 mil exercícios
gratuitos
4,8/5 classificação
nas lojas de apps
Cursos gratuitos em
vídeo, ebooks e audiobooks