01 / 26
Lógica de Programação · Semana 18 · Dia 1 (aulas 1 e 2)

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.

ProfessorGuilherme Antunes CursoTécnico em Desenvolvimento de Sistemas ConteúdoUnidade 5 · Componente 1 CódigosSISANO1C1B3S18A1 · A2
02 / 26
Objetivos do dia

Ao final, você será capaz de.

01

Distinguir comentário redundante de comentário eficaz, escrevendo o "porquê" em vez do "como"

02

Escrever docstrings com propósito, parâmetros, retorno e exceções

03

Aplicar o padrão AAA — Arrange, Act, Assert — para organizar qualquer teste

04

Criar asserts simples, interpretar a falha e escolher bons casos de teste

Onde estamos: na Semana 17 vocês quebraram o programa em funções. Hoje essas funções ganham manual (documentação) e garantia (teste) — nessa ordem, porque não dá para provar uma promessa que ninguém escreveu.
03 / 26
Parte 1 Documentação · ponto de partida

O código é o edifício, a documentação é a planta

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?

O dado incômodo: um programador passa muito mais tempo lendo código do que escrevendo. Documentar não é burocracia — é reduzir o custo de todas as leituras futuras, inclusive as suas.
04 / 26
Construindo o conceito

Comentário é o "porquê", não o "como"

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çãoCódigo ruim (redundante)Código limpo (expressivo)
Nomenclaturav = 100 # define v como 100limite_tentativas_login = 10
Lógicax = x + 1 # soma 1 ao xcontador_usuarios += 1
Fica a dica: antes de escrever um comentário, tente renomear a variável. Na maioria das vezes o comentário desaparece sozinho — e um nome bom nunca fica desatualizado.
05 / 26
Construindo o conceito

O comentário que vale ouro

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.

Sem contexto — ninguém ousa mexer

valor_final = preco * 1.15
De onde veio esse 1.15? Daqui a seis meses ninguém sabe se pode alterar — e o número vira intocável.

Com contexto — dá para manter

# Fator 1.15 aplicado por causa da alteração
# na Lei Tributária 1234 (agosto/2025).
valor_final = preco * 1.15
Teste do comentário útil: ele responde a uma pergunta que o código não responde? Se a resposta for não, apague.
06 / 26
Docstring

O contrato da função

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.

1

Propósito

Um resumo curto do que a função faz — de preferência em uma linha.

2

Parâmetros

Nome, tipo e significado de cada dado esperado na entrada.

3

Retorno

Natureza e tipo do dado devolvido a quem chamou.

4

Exceções

Quais erros a função pode disparar e em que condição.

Por que isso importa: quem usa sua função deveria conseguir usá-la sem abrir o corpo dela. Se precisou abrir, a docstring falhou.
07 / 26
Sintaxe em Python

Como se escreve na prática

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

O programa consegue ler isso

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.
...
A docstring fica guardada na memória junto com a função. O comentário comum não — ele some na hora em que o código é interpretado.
08 / 26
Vocabulário técnico

Comentário x docstring

Comentário

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.

Docstring

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érioComentário #Docstring """
PúblicoQuem mantém o códigoQuem consome a função
Acessível em execuçãoNão — descartadoSim — via __doc__ / help()
FerramentasIgnoradoVira manual automático (Sphinx)
09 / 26
Pause e responda

Qual é a distinção fundamental?

Entre um comentário comum e uma docstring, no contexto do desenvolvimento de software:

ADocstrings documentam a interface e o propósito da função ✓
BComentários comuns são exportados para manuais externos
CDocstrings explicam linha por linha o código interno
DComentários substituem a necessidade de testes formais
Por que A: a docstring descreve o contrato — o que entra e o que sai —, não a implementação. Detalhe de implementação muda toda semana; contrato só muda quando a função muda de propósito.
10 / 26
Mercado

Documentação que se escreve sozinha

Porque a docstring é um dado acessível pelo programa, ferramentas conseguem varrer o projeto inteiro e montar um manual navegável a partir dela.

1

Código-fonte + docstrings
a informação mora ao lado da função

2

Ferramenta de extração
Sphinx (Python), Doxygen (C/C++), JSDoc

3

Manual web ou PDF
gerado a cada versão, sem trabalho manual

Fonte única da verdade: manter a documentação grudada ao código garante que ela seja atualizada no mesmo commit da mudança. Manual em pasta separada envelhece em semanas.
11 / 26
Armadilha

Documentação errada é pior que nenhuma

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.

A docstring mente

def aplicar_desconto(preco):
    """Aplica 10% de desconto."""
    return preco * 0.80   # mudou para 20%

Regra do time

  • Mudou o comportamento? Atualize a docstring no mesmo momento
  • Mudou o parâmetro? Atualize Args
  • Documentação entra na revisão de código, como o resto
Atenção: um bug de documentação não quebra o programa — quebra a confiança. E confiança quebrada faz todo mundo voltar a ler o corpo de todas as funções.
12 / 26
Parte 2 Testes unitários · ponto de partida

O efeito dominó no código

A 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?

Nome disso no mercado: regressão — quando algo que funcionava para de funcionar. Testar tudo na mão a cada alteração é inviável; por isso o teste vira código.
13 / 26
Construindo o conceito

A menor engrenagem do sistema

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.

Topo · UI / E2E

Simula o usuário de ponta a ponta. Lento, caro, quebra fácil. Poucos.

Meio · Integração

Verifica se as partes conversam entre si (banco, API). Alguns.

Base · Unitários

Testam uma função isolada. Rápidos e baratos. Muitos.

14 / 26
Construindo o conceito

O poder do isolamento

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.

A regra de ouro: se o teste acessa a internet, o banco de dados ou o relógio do sistema, ele não é unitário. Ele passou a testar duas coisas ao mesmo tempo.
Benefício direto: quando o teste falha, você já sabe onde está o erro. Sem isolamento, uma falha vira uma investigação de meia hora para descobrir qual das cinco peças quebrou.
15 / 26
Padrão estrutural

Todo teste tem três atos

A

Arrange · preparar
Configurar o cenário e o gabarito esperado. O mise en place do teste.

A

Act · agir
Chamar a função que será testada, guardando o que ela devolver.

A

Assert · validar
Confrontar o resultado obtido com o gabarito. Sem meio-termo.

O 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.
16 / 26
Sintaxe em Python

Como o assert se comporta

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!

Anatomia

1

assert — a palavra-chave

2

condição — deve resultar em True

3

mensagem (opcional) — o que aparece quando falha

Escreva sempre a mensagem. "AssertionError" sozinho não diz nada às 23h de uma sexta-feira.
17 / 26
Desafio QA · carrinho de compras

Provando que o desconto fecha

Você é da equipe de qualidade de um e-commerce. O setor financeiro exige provas de que a função de desconto é infalível.

A função sob teste

def calcular_desconto(valor_original, percentual):
    """Devolve o valor já com o desconto aplicado."""
    desconto = valor_original * (percentual / 100)
    return valor_original - desconto
Repare: a função da Parte 1 chegou aqui documentada. A docstring é o gabarito que o teste vai cobrar.

O teste, em três atos

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()
18 / 26
Lendo o resultado

Verde, vermelho e nada no meio

Passou

Sucesso! O teste unitário passou.

Silêncio é boa notícia: o assert não interrompeu nada e o programa chegou ao print final.

Falhou — alguém trocou o cálculo

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.

Teste não tem "mais ou menos": ou o resultado bate com o gabarito, ou existe defeito. Essa dureza é justamente o que dá segurança para mexer no código.
19 / 26
Pause e responda

No padrão AAA, o que faz o assert?

AConfigurar as variáveis e o estado inicial do teste
BChamar a função principal que será avaliada no código
CValidar se o resultado obtido é o esperado ✓
DApagar os dados temporários após a execução da função
Por que C: preparar é Arrange, chamar é Act. O Assert é o único momento em que o teste emite um veredito — e é ele que transforma execução em verificação.
20 / 26
Boas práticas

Um teste só não basta

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 casoO que verificaExemplo no desconto
Caminho felizUso normal, dados válidos200 com 15% → 170
BordaLimites: zero, vazio, máximo200 com 0% → 200 · 100% → 0
Entrada inválidaO que deveria falhar falhapercentual negativo
Regra prática: um teste, um comportamento. Se o nome da função de teste precisar de "e" (testar_desconto_e_frete), separe em dois — assim a falha aponta direto para a causa.
21 / 26
Montando a suíte

Três testes, um segundo

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
Malha de proteção: a partir de agora, qualquer alteração em calcular_desconto é conferida por três testes em menos de um segundo.
Repare no teste.__name__: é o mesmo mecanismo da docstring — o programa consegue ler informações sobre suas próprias funções.
22 / 26
Pause e responda

Qual destes não é um teste unitário?

AVerificar se calcular_media([8, 6]) devolve 7
BVerificar se o cadastro grava o aluno no banco de dados ✓
CVerificar se eh_par(3) devolve False
DVerificar se dividir por zero dispara o erro esperado
Por que B: gravar no banco envolve outra peça além da função — é um teste de integração. Continua sendo importante, mas fica no meio da pirâmide, não na base.
23 / 26
Colocando em prática · fecho do dia

Documentar e provar a mesma função

1

Escolha uma função importante do sistema que você já escreveu nas semanas anteriores.

2

Adicione a docstring com propósito, parâmetros e retorno — e um comentário de negócio explicando alguma regra.

3

Escreva três testes para ela: caminho feliz, um caso de borda e uma entrada inválida, usando o padrão AAA.

4

Quebre a função de propósito (troque um sinal) e confirme que pelo menos um teste acusa. Depois desfaça.

Critério de pronto: passe o código para o colega ao lado escondendo o corpo da função. Se ele souber usá-la só com a docstring — e os testes passarem —, está pronto.
24 / 26
Então ficamos assim…

O que vimos hoje ✓

  • Comentário eficaz → explica o porquê (regra de negócio), nunca o como
  • Docstring → contrato da função: propósito, parâmetros, retorno, exceções; acessível por help()
  • Teste unitário → verifica a menor unidade, isolada; se acessa internet ou banco, não é unitário
  • Padrão AAA → Arrange (preparar) · Act (agir) · Assert (validar)
  • Bons casos → caminho feliz + bordas + entradas inválidas
Próximo encontro

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.

25 / 26
Cola de bolso

Documentação e testes em oito linhas

  • # comenta uma linha · """…""" logo abaixo do def vira docstring
  • Docstring: o que faz → Args → Returns → Raises
  • Antes de comentar, tente renomear a variável; mudou o código, muda a documentação
  • assert condicao, "mensagem" — a menor forma de teste em Python
  • Ordem sagrada: Arrange → Act → Assert
  • Um teste, um comportamento; o nome do teste descreve o que se espera
  • Gabarito calculado na mão, nunca pela mesma fórmula que está sendo testada
  • Achou um bug? Escreva primeiro o teste que o reproduz, depois corrija
As duas perguntas do dia: "alguém usa essa função sem ler o corpo dela?" e "se eu quebrar essa função agora, alguma coisa avisa?".
26 / 26
Referências

De onde veio cada coisa

SEDUC-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