Documentação e
testes unitários
Primeiro a função promete um comportamento. Depois a gente escreve o código que cobra a promessa — e passa a dormir tranquilo depois de cada alteração.
Primeiro a função promete um comportamento. Depois a gente escreve o código que cobra a promessa — e passa a dormir tranquilo depois de cada alteração.
Distinguir comentário redundante de comentário eficaz, escrevendo o "porquê" em vez do "como"
Escrever docstrings com propósito, parâmetros, retorno e exceções
Aplicar o padrão AAA — Arrange, Act, Assert — para organizar qualquer teste
Criar asserts simples, interpretar a falha e escolher bons casos de teste
Imagine um engenheiro que entrega um prédio pronto, mas sem a planta arquitetônica nem o mapa elétrico. Anos depois é preciso trocar um cano: os operários vão quebrar as paredes às cegas.
Virem e conversem: se você não entende seu próprio código depois de um mês, como espera que outra pessoa entenda? E qual é o impacto, para o usuário, de um aparelho que chega sem manual?
Comentar cada linha traduzindo a sintaxe é ruído: o leitor já sabe ler Python. O comentário só se paga quando conta algo que o código não consegue dizer sozinho.
| Situação | Código ruim (redundante) | Código limpo (expressivo) |
|---|---|---|
| Nomenclatura | v = 100 # define v como 100 | limite_tentativas_login = 10 |
| Lógica | x = x + 1 # soma 1 ao x | contador_usuarios += 1 |
Use comentários para justificar decisões de negócio que a sintaxe não revela. Números mágicos, exceções à regra, contornos temporários: tudo isso precisa de origem documentada.
valor_final = preco * 1.15
# Fator 1.15 aplicado por causa da alteração
# na Lei Tributária 1234 (agosto/2025).
valor_final = preco * 1.15
A docstring é o texto entre aspas triplas na primeira linha de uma função, classe ou módulo. Ela formaliza a interface pública: o que entra, o que sai, o que pode dar errado.
Um resumo curto do que a função faz — de preferência em uma linha.
Nome, tipo e significado de cada dado esperado na entrada.
Natureza e tipo do dado devolvido a quem chamou.
Quais erros a função pode disparar e em que condição.
def calcular_area(raio):
"""
Calcula a área de um círculo.
Args:
raio (float): O raio do círculo.
Returns:
float: A área do círculo.
Raises:
ValueError: se o raio for negativo.
"""
if raio < 0:
raise ValueError("Raio negativo")
return 3.14 * raio ** 2
print(calcular_area.__doc__)
help(calcular_area)
Calcula a área de um círculo.
Args:
raio (float): O raio do círculo.
Returns:
float: A área do círculo.
...
Anotação interna, para quem vai alterar o código. Explica decisões, avisos, gambiarras conscientes.
É o bilhete colado na parede da sala de máquinas.Documento público, para quem vai usar a função. Descreve entradas, saídas e comportamento.
É o manual do usuário na caixa do produto.| Critério | Comentário # | Docstring """ |
|---|---|---|
| Público | Quem mantém o código | Quem consome a função |
| Acessível em execução | Não — descartado | Sim — via __doc__ / help() |
| Ferramentas | Ignorado | Vira manual automático (Sphinx) |
Entre um comentário comum e uma docstring, no contexto do desenvolvimento de software:
Porque a docstring é um dado acessível pelo programa, ferramentas conseguem varrer o projeto inteiro e montar um manual navegável a partir dela.
Código-fonte + docstrings
a informação mora ao lado da função
Ferramenta de extração
Sphinx (Python), Doxygen (C/C++), JSDoc
Manual web ou PDF
gerado a cada versão, sem trabalho manual
Quando o código muda e a docstring fica para trás, ela deixa de ser ajuda e vira armadilha: o leitor confia em uma promessa que o programa não cumpre mais.
def aplicar_desconto(preco):
"""Aplica 10% de desconto."""
return preco * 0.80 # mudou para 20%
ArgsA docstring diz que a função aplica 10% de desconto. Mas quem garante que ela ainda faz isso depois da alteração de ontem? Você corrige um erro no login, testa, funciona — e sem perceber quebra a finalização de compras.
Virem e conversem: quem aqui já alterou uma linha achando que estava consertando algo e acabou quebrando o programa inteiro? Como garantir que a mudança de hoje não quebre o que já funcionava?
Testes unitários são fragmentos de código que testam a menor unidade da aplicação — geralmente uma função — em condições controladas.
Eles são a base da pirâmide de testes porque são rápidos e baratos: rodam em milissegundos e podem ser executados centenas de vezes por dia.
Simula o usuário de ponta a ponta. Lento, caro, quebra fácil. Poucos.
Verifica se as partes conversam entre si (banco, API). Alguns.
Testam uma função isolada. Rápidos e baratos. Muitos.
Pense em uma fábrica de carros. Como sabemos se o motor funciona? Ligamos o motor isolado, numa bancada, antes de instalar no carro. Se falhar, o problema é no motor — não no pneu.
Arrange · preparar
Configurar o cenário e o gabarito esperado. O mise en place do teste.
Act · agir
Chamar a função que será testada, guardando o que ela devolver.
Assert · validar
Confrontar o resultado obtido com o gabarito. Sem meio-termo.
assert é o juiz da partida: se ele apita falta, existe um bug na lógica do programa. Um teste sem assert não testa nada — apenas executa código.
O assert é nativo do Python: avalia uma condição; se for verdadeira, o programa continua em silêncio; se for falsa, ele trava e lança um AssertionError.
assert 2 + 2 == 4 # passa, silêncio
assert 2 + 2 == 5, "Erro na soma!"
Traceback (most recent call last): File "teste.py", line 2, in <module> AssertionError: Erro na soma!
assert — a palavra-chave
condição — deve resultar em True
mensagem (opcional) — o que aparece quando falha
Você é da equipe de qualidade de um e-commerce. O setor financeiro exige provas de que a função de desconto é infalível.
def calcular_desconto(valor_original, percentual):
"""Devolve o valor já com o desconto aplicado."""
desconto = valor_original * (percentual / 100)
return valor_original - desconto
def testar_calculo_de_desconto():
# 1. Arrange (preparar)
valor_produto = 200.0
desconto_aplicado = 15.0
resultado_esperado = 170.0 # gabarito
# 2. Act (agir)
resultado_obtido = calcular_desconto(
valor_produto, desconto_aplicado)
# 3. Assert (validar)
assert resultado_obtido == resultado_esperado, \
"Erro matemático grave no desconto!"
print("Sucesso! O teste unitário passou.")
testar_calculo_de_desconto()
Sucesso! O teste unitário passou.
Silêncio é boa notícia: o assert não interrompeu nada e o programa chegou ao print final.
Traceback (most recent call last): File "teste.py", line 14, in testar_calculo_de_desconto AssertionError: Erro matemático grave no desconto!
O teste apontou o arquivo, a linha e a função. O bug foi capturado antes de chegar ao cliente.
Testar apenas o caso que você já sabe que funciona dá falsa sensação de segurança. Um bom conjunto cobre três frentes:
| Tipo de caso | O que verifica | Exemplo no desconto |
|---|---|---|
| Caminho feliz | Uso normal, dados válidos | 200 com 15% → 170 |
| Borda | Limites: zero, vazio, máximo | 200 com 0% → 200 · 100% → 0 |
| Entrada inválida | O que deveria falhar falha | percentual negativo |
def testar_sem_desconto():
assert calcular_desconto(200, 0) == 200, \
"0% deveria manter o valor"
def testar_desconto_total():
assert calcular_desconto(200, 100) == 0, \
"100% deveria zerar o valor"
def testar_desconto_comum():
assert calcular_desconto(200, 15) == 170, \
"15% de 200 deveria dar 170"
# executor simples da suíte
for teste in (testar_sem_desconto,
testar_desconto_total,
testar_desconto_comum):
teste()
print("OK:", teste.__name__)
OK: testar_sem_desconto OK: testar_desconto_total OK: testar_desconto_comum
calcular_desconto é conferida por três testes em menos de um segundo.
teste.__name__: é o mesmo mecanismo da docstring — o programa consegue ler informações sobre suas próprias funções.
calcular_media([8, 6]) devolve 7eh_par(3) devolve FalseEscolha uma função importante do sistema que você já escreveu nas semanas anteriores.
Adicione a docstring com propósito, parâmetros e retorno — e um comentário de negócio explicando alguma regra.
Escreva três testes para ela: caminho feliz, um caso de borda e uma entrada inválida, usando o padrão AAA.
Quebre a função de propósito (troque um sinal) e confirme que pelo menos um teste acusa. Depois desfaça.
help()O teste avisou que existe um bug — mas onde? No Dia 2: técnicas de depuração (breakpoint, passo a passo, inspeção de variáveis) e o mini-kata de TDD.
# comenta uma linha · """…""" logo abaixo do def vira docstringassert condicao, "mensagem" — a menor forma de teste em PythonSEDUC-SP. Educação Profissional Paulista — Técnico em Desenvolvimento de Sistemas. Lógica de Programação, Unidade 5, Componente 1 — Documentação, testes unitários e depuração (Semana 18, aulas 1 e 2). Códigos: SISANO1C1B3S18A1 e A2.
BECK, K. Desenvolvimento guiado por testes. Porto Alegre: Bookman, 2010.
MARTIN, R. C. Código limpo: habilidades práticas do Agile Software. Rio de Janeiro: Alta Books, 2009.
OSHEROVE, R. The art of unit testing. Nova Iorque: Manning Publications, 2013.
SHARMA, A. Tutorial de docstrings em Python. Datacamp, 18 jul. 2024. Disponível em: datacamp.com. Acesso em: 23 abr. 2026.
Aula compilada (dobradinha) · adaptação para apresentação HTML por Guilherme Antunes