Módulo 15 - Testes automatizados
Testando casos de borda
11 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 01/07/2026
O que você vai aprender
- Distinguir caso normal, casos de borda e entradas inválidas.
- Escolher os valores que mais provavelmente escondem bugs.
- Testar que uma função levanta a exceção certa em entrada inválida.
- Aplicar a regra de um teste para cada comportamento.
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: Testando casos de borda.
Os objetivos desta aula. Distinguir caso normal, casos de borda e entradas inválidas. Escolher os valores que mais provavelmente escondem bugs. Testar que uma função levanta a exceção certa em entrada inválida. Aplicar a regra de um teste para cada comportamento.
Veja o essencial, parte por parte.
Onde moram os bugs. Teste o caso normal, mas não pare nele: os bugs vivem nas bordas.
Testando entradas inválidas. Testar dez variações do caso feliz e nenhuma borda: sensação falsa de cobertura.
Um teste por comportamento. Repare que, no exemplo da média, cada teste verifica um comportamento e tem um nome que o descreve: test_caso_normal, test_um_elemento, test_com_negativos, test_lista_vazia_levanta_erro.
Esse foi o resumo do essencial. Para se aprofundar, leia a aula completa e responda os exercícios.
Onde moram os bugs
Escrever um teste que passa é fácil quando você só testa o caso para o qual pensou a função. Uma função de média com a lista [2, 4, 6] devolve 4, o teste passa, e dá aquela sensação de dever cumprido. O problema é que o usuário real, ou o resto do programa, não manda só listas bem comportadas. Uma hora chega uma lista vazia, e a sua função tenta dividir por zero e explode. É nas bordas, nos limites do que a função aceita, que os bugs se escondem. Testar só o caminho feliz é como conferir se um carro anda em linha reta e nunca testar a curva.
Existe um pequeno repertório de bordas que vale checar em quase toda função. Se ela recebe uma coleção, teste com a coleção vazia e com um único elemento. Se recebe números, teste o zero, um negativo e, quando houver, o maior valor permitido. Se trabalha com posições, teste o primeiro e o último item, onde erros de um a mais ou um a menos costumam aparecer. Se há um limite, como maior de idade a partir de 18, teste 17, 18 e 19, os valores em torno da fronteira. Essa lista curta pega uma fatia enorme dos bugs reais.
import unittest
def media(valores):
if not valores:
raise ValueError("lista vazia nao tem media")
return sum(valores) / len(valores)
class TestMedia(unittest.TestCase):
def test_caso_normal(self):
self.assertEqual(media([2, 4, 6]), 4)
def test_um_elemento(self):
self.assertEqual(media([10]), 10)
def test_com_negativos(self):
self.assertEqual(media([-2, 2]), 0)
def test_lista_vazia_levanta_erro(self):
with self.assertRaises(ValueError):
media([])Caso normal, borda de um elemento, negativos e a entrada inválida (lista vazia).
Testando entradas inválidas
Repare no último teste do exemplo. Uma lista vazia não é apenas uma borda, é uma entrada inválida: não faz sentido tirar a média de nada. A função foi escrita para reagir a isso levantando um ValueError, como você viu no módulo de exceções. E o teste verifica justamente esse comportamento com self.assertRaises. Ele diz espero que o bloco abaixo levante um ValueError. Se levantar, o teste passa; se a função não levantar nada, ou levantar outro erro, o teste falha. Testar o erro esperado é tão importante quanto testar o resultado certo.
# No pytest, o mesmo teste de excecao fica assim:
import pytest
def test_lista_vazia_levanta_erro():
with pytest.raises(ValueError):
media([])
# python -m pytest -> passa se media([]) levantar ValueError.A versão pytest usa pytest.raises, com a mesma ideia do assertRaises do unittest.
Ao testar entradas inválidas, o objetivo não é fazer a função aceitar qualquer coisa, e sim garantir que ela falha de um jeito previsto e claro, em vez de devolver um resultado errado em silêncio ou estourar um erro confuso. Um programa confiável é aquele que se recusa a fazer o que não faz sentido, e faz isso de forma explícita. O teste registra essa promessa: se um dia alguém remover a checagem da lista vazia, o teste test_lista_vazia_levanta_erro falha e avisa que a proteção sumiu.
Um teste por comportamento
Repare que, no exemplo da média, cada teste verifica um comportamento e tem um nome que o descreve: test_caso_normal, test_um_elemento, test_com_negativos, test_lista_vazia_levanta_erro. Essa é a regra de ouro. Resista à tentação de espremer cinco verificações diferentes dentro de um único método só porque tratam da mesma função. Quando um teste cobre um só comportamento, uma falha aponta com precisão o que quebrou, e o nome do teste já conta a história antes mesmo de você olhar o código. Quando um teste gigante mistura tudo, uma falha diz apenas que algo naquele bolo deu errado, e você volta a caçar na mão, justamente o que os testes vieram evitar. Nomes claros e testes pequenos transformam a suíte em uma lista legível do que o seu código promete fazer.
Teste rápido
Por que vale escrever um teste separado para cada comportamento, em vez de um teste grande?
Perguntas frequentes
- O que é exatamente um caso de borda?
- É uma entrada no limite ou fora do comum, onde o código tem mais chance de falhar: coleção vazia, zero, número negativo, o maior valor permitido, o primeiro e o último item de uma sequência. Bugs se concentram nesses pontos, por isso vale testá-los além do caso típico.
- Como testo que uma função levanta uma exceção?
- No unittest, use with self.assertRaises(TipoDoErro): e chame a função dentro do bloco. No pytest, use with pytest.raises(TipoDoErro):. O teste passa se aquela exceção for levantada e falha se a função não levantar nada ou levantar outro erro.
- Quantos casos de borda devo testar por função?
- Não há número fixo. Cubra as bordas que fazem sentido para aquela função: vazio e um elemento se ela recebe coleção; zero e negativo se recebe números; os valores em torno de um limite quando existe uma fronteira. A ideia é pensar onde a função poderia tropeçar.
- Posso juntar vários asserts em um só método de teste?
- Pode, mas evite misturar comportamentos diferentes. Se um teste verifica cinco coisas distintas e falha, você não sabe qual delas quebrou. Prefira um teste por comportamento, com nome descritivo. Vários asserts que checam o mesmo comportamento, isso sim, costumam conviver bem.
- Testar entrada inválida não é procurar problema?
- Ao contrário, é garantir que o programa reage bem quando recebe algo que não faz sentido. O objetivo não é aceitar qualquer coisa, e sim confirmar que a função falha de um jeito previsto e claro, como levantar um ValueError, em vez de devolver um resultado errado calada.
- Se eu testo o caso normal, não estou coberto?
- Só em parte. O caso feliz mostra que a função anda em linha reta, mas os bugs moram nas curvas: a lista vazia, o zero, o limite exato, a entrada inválida. Testar apenas o caminho comum passa uma falsa sensação de segurança, porque deixa de fora justamente onde as falhas aparecem.
Fontes
Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.