Professor: Gabriel Soares Baptista
Quando uma equipe deixa os testes para o fim, vários problemas aparecem:
Segundo Sommerville, testar tem dois objetivos principais:
Se uma função passa em todos os testes unitários, isso já prova que o sistema inteiro está pronto para entrega?
Não.
Ainda faltam, por exemplo:
| Nível | Pergunta principal |
|---|---|
| Unitário | Esta função, método ou classe pequena funciona? |
| Integração / componente | Essas partes funcionam bem juntas? |
| Sistema | O sistema completo se comporta como esperado? |
| Release | Esta versão está pronta para sair da equipe? |
| Aceitação | O cliente considera o sistema adequado para uso real? |
No capítulo 8, Sommerville organiza os testes de desenvolvimento em três níveis:
Hoje vamos focar em três ideias:
Teste unitário é o teste de uma unidade pequena e isolada.
Exemplos:
Passar em testes unitários não garante:
Sommerville resume um teste automatizado em três partes:
Passo 1. Escreva uma regra simples.
def calcular_desconto(valor: float, percentual: float) -> float:
if valor < 0:
raise ValueError("valor nao pode ser negativo")
if percentual < 0 or percentual > 100:
raise ValueError("percentual invalido")
return valor * (percentual / 100)
Passo 2. Teste o comportamento normal.
from desconto import calcular_desconto
def test_calcula_desconto_de_10_porcento():
assert calcular_desconto(200.0, 10.0) == 20.0
Passo 3. Teste a entrada inválida.
import pytest
from desconto import calcular_desconto
def test_lanca_erro_para_valor_negativo():
with pytest.raises(ValueError):
calcular_desconto(-50.0, 10.0)
Se a regra for:
quais grupos de entrada você deveria testar?
Passo 1. Escreva a regra.
def calcular_frete(total_pedido: float) -> float:
if total_pedido < 0:
raise ValueError("total invalido")
if total_pedido >= 200:
return 0.0
return 15.0
Passo 2. Use parametrize para cobrir grupos diferentes.
import pytest
@pytest.mark.parametrize(
"total, frete_esperado",
[
(50.0, 15.0),
(199.99, 15.0),
(200.0, 0.0),
(350.0, 0.0),
],
)
def test_calcular_frete(total, frete_esperado):
assert calcular_frete(total) == frete_esperado
50.0 e 199.99 cobrem abaixo do limite200.0 cobre o caso de borda350.0 cobre acima do limitePasso 3. Adicione o erro esperado.
def test_total_negativo_dispara_erro():
with pytest.raises(ValueError):
calcular_frete(-1.0)
uv + pytestFluxo simples para executar os testes em Python:
uv venv
source .venv/bin/activate
uv pip install pytest
pytest -q
Estrutura mínima:
projeto/
├── desconto.py
└── tests/
└── test_desconto.py
Às vezes ela depende de:
Você pode usar objetos de teste como:
No TDD, o desenvolvimento acontece em passos pequenos, intercalando:
Sem TDD, muita gente faz assim:
Com TDD, a lógica muda:
Nesta aula, vamos usar a convenção:
No TDD, o vermelho inicial não é fracasso.
Ele mostra que:
Requisito pequeno: pedido com valor maior ou igual a R$ 200,00 tem frete zero.
Primeiro, escrevemos o teste:
from checkout import calcular_frete
def test_pedido_com_200_reais_ou_mais_tem_frete_gratis():
assert calcular_frete(200.0) == 0.0
Ao rodar, ele falha.
Vermelho.
Agora implementamos o mínimo:
def calcular_frete(total_pedido: float) -> float:
return 0.0
O teste passa.
Verde.
Agora escrevemos um segundo teste:
def test_pedido_abaixo_de_200_reais_paga_frete_padrao():
assert calcular_frete(150.0) == 15.0
Ele falha.
Vermelho novamente.
Implementamos o mínimo para os dois testes:
def calcular_frete(total_pedido: float) -> float:
if total_pedido >= 200.0:
return 0.0
return 15.0
Agora os dois passam.
Verde novamente.
Agora refatoramos sem mudar o comportamento:
FRETE_PADRAO = 15.0
LIMITE_FRETE_GRATIS = 200.0
def calcular_frete(total_pedido: float) -> float:
if total_pedido >= LIMITE_FRETE_GRATIS:
return 0.0
return FRETE_PADRAO
Todos os testes continuam passando.
Azul.
Sommerville destaca benefícios como:
TDD ajuda muito, mas não substitui:
Sommerville separa o teste de release do teste de desenvolvimento.
Diferenças principais:
Uma abordagem central do teste de release é:
Sommerville também destaca testes de cenário.
Eles partem de histórias realistas de uso, por exemplo:
Teste de aceitação é parte dos testes de usuário.
A pergunta central aqui é:
o sistema está bom o suficiente para uso real pelo cliente?
Não apenas funcionalidade, mas também:
| Tipo | O que verifica? |
|---|---|
| Unitário | Se uma unidade isolada funciona corretamente |
| Aceitação | Se o sistema está adequado para uso do ponto de vista do cliente |
Exemplo:
calcular_frete(200.0) == 0.0R$ 0,00 no uso realNa prática, pode haver aceitação condicional.
Isso acontece quando:
Guarde esta ideia central:
Testar não é uma atividade única.
É um conjunto de verificações em níveis diferentes.