01 / 25
Lógica de Programação · Semana 18 · Dia 2 (aulas 3 e 4)

Depuração e
mini-kata TDD

O teste avisou que existe um bug. Agora é preciso encontrá-lo — e depois inverter o jogo, escrevendo o teste antes do código. Fecho da semana da qualidade.

ProfessorGuilherme Antunes CursoTécnico em Desenvolvimento de Sistemas ConteúdoUnidade 5 · Componente 1 CódigosSISANO1C1B3S18A3 · A4
02 / 25
Objetivos do dia

Ao final, você será capaz de.

01

Diferenciar erro de sintaxe, de execução e de lógica — e saber qual deles o computador não avisa

02

Usar breakpoints, passo a passo e inspeção de variáveis para achar a causa raiz

03

Executar o ciclo red-green-refactor em uma função pequena, do zero

04

Integrar documentação, teste e depuração em um ciclo completo, trabalhando em dupla

Onde estamos: no Dia 1 a função ganhou manual e garantia. Hoje aprendemos a investigar quando a garantia acusa problema — e a inverter a ordem para que o problema nem chegue a existir.
03 / 25
Parte 1 Depuração · ponto de partida

Escrever é rápido. Achar é que demora

A média de um programador experiente é gastar mais tempo procurando a causa de um erro do que digitando a correção. A correção costuma ter uma linha; a investigação, três horas.

Virem e conversem: qual foi o bug mais difícil que vocês já enfrentaram? O que vocês tentaram — e o que finalmente revelou a causa?

Origem da palavra: em 1947, a equipe de Grace Hopper encontrou literalmente uma mariposa presa em um relé do computador Mark II e colou o inseto no caderno de registro: "first actual case of bug being found". Depurar é, desde então, tirar o bicho da máquina.
04 / 25
Construindo o conceito

Três tipos de erro, três dificuldades

Sintaxe

O código nem roda. O interpretador aponta o arquivo e a linha.

Fácil: falta de dois-pontos, parêntese aberto, indentação errada.

Execução (runtime)

Roda e para no meio, com mensagem de erro.

Médio: ZeroDivisionError, IndexError, TypeError.

Lógica (semântico)

Roda até o fim, sem reclamar — e entrega o resultado errado.

Difícil: ninguém avisa. É aqui que a depuração vale ouro.
Atenção: o erro de lógica é o único que passa despercebido pelo computador. A média sai errada, o estoque fica negativo, o desconto dobra — e o programa continua dizendo que está tudo bem.
05 / 25
Primeira ferramenta

Ler o traceback inteiro

Traceback (most recent call last):
  File "app.py", line 22, in <module>
    print(media_turma(notas))
  File "app.py", line 15, in media_turma
    return soma / len(lista)
ZeroDivisionError: division by zero

Como se lê

1

Comece pela última linha: o tipo do erro e a mensagem

2

Suba: a linha imediatamente acima mostra onde estourou

3

Continue subindo para ver quem chamou quem

4

A causa raiz costuma estar na origem dos dados, não no ponto do estouro

Aqui o erro estourou na divisão, mas a causa é a lista vazia que chegou até ela.
06 / 25
Segunda ferramenta

O print estratégico

Colocar print nos pontos-chave é a técnica mais antiga e ainda a mais usada do mundo. Funciona — desde que os prints sejam rotulados.

Print inútil

print(x)
print(y)
print(total)
3
0
0

Print que investiga

print("[loop] i =", i, "| total =", total)
[loop] i = 0 | total = 8
[loop] i = 1 | total = 6
[loop] i = 2 | total = 7
Limite da técnica: o print mostra o que você lembrou de imprimir, no ponto em que você achou que era o problema. E dá para esquecer um deles no código entregue.
07 / 25
Terceira ferramenta

O depurador da IDE

O depurador (debugger) permite congelar o programa em qualquer ponto e olhar a memória por dentro, sem alterar uma linha do código.

ComandoO que fazQuando usar
BreakpointMarca a linha onde a execução deve pararAntes do trecho suspeito
Step overExecuta a linha atual e para na próximaAvançar dentro do laço
Step intoEntra na função chamada nessa linhaSuspeita da função chamada
Step outTermina a função atual e volta a quem chamouJá viu o que precisava
ContinueRoda até o próximo breakpointPular iterações sem interesse
Atalho universal: na maioria das IDEs, F9 marca o breakpoint, F5 inicia a depuração e F10 avança linha a linha.
08 / 25
Inspeção de variáveis

Ver a memória mudando

Com o programa congelado, os painéis Locals (todas as variáveis do escopo atual) e Watch (as expressões que você escolheu vigiar) mostram os valores naquele exato instante.

Para que serve num laço

  • Acompanhar o acumulador a cada iteração
  • Conferir se o contador chega ao valor esperado
  • Descobrir em qual iteração o valor sai do trilho
  • Verificar se a condição de parada vai mesmo ser satisfeita
A pergunta certa não é "onde está o erro?", e sim "em que momento a variável deixou de valer o que deveria?". O painel de inspeção responde exatamente isso.
Erros semânticos em acumuladores — como sobrescrever em vez de somar — são invisíveis na sintaxe e só aparecem observando o estado.
09 / 25
Caso clássico

O bug que não dá erro

Com bug — sobrescreve

notas = [8, 6, 7, 9]
total = 0

for nota in notas:
    total = nota          # ← sobrescreve!

print("Média:", total / len(notas))
Média: 2.25   (o certo seria 7.5)

O que o Watch mostra

i0

nota=8 → total=8 (ok por acaso)

i1

nota=6 → total=6 ← aqui!

i2

nota=7 → total=7

i3

nota=9 → total=9

Bastava trocar = por +=. Mas note: o programa rodou até o fim sem reclamar — só a inspeção do estado revelou o defeito.
10 / 25
Pause e responda

Para que serve o Watch/Locals?

Durante a depuração de uma estrutura de repetição, qual é a finalidade principal da ferramenta de inspeção de variáveis?

ACorrigir automaticamente o erro lógico de sintaxe
BMonitorar a alteração dos dados a cada iteração ✓
CPular a execução do laço de repetição inteiro
DReescrever a docstring da função sendo analisada
Por que B: nenhuma ferramenta corrige lógica por você — ela apenas mostra o estado. Quem interpreta o estado e formula a hipótese é o programador.
11 / 25
Método

Depurar é método científico

1

Reproduzir — encontre a entrada exata que provoca o erro. Bug que não se reproduz não se corrige.

2

Isolar — reduza o cenário ao menor trecho que ainda falha (bissecção: corte pela metade, teste, repita).

3

Levantar hipótese — "acho que o total está sendo sobrescrito no laço". Uma hipótese por vez.

4

Testar a hipótese — breakpoint + inspeção. Confirmou? Siga. Não confirmou? Descarte e volte ao passo 3.

5

Corrigir e blindar — arrume a causa e escreva um teste unitário que falharia antes da correção.

Antipadrão: mudar várias coisas ao mesmo tempo até "funcionar". Se o programa passar a funcionar, você não vai saber por quê — e o bug volta na semana seguinte.
12 / 25
Técnica de bolso

Explique para o patinho

A técnica do rubber duck debugging consiste em explicar o código linha por linha, em voz alta, para um objeto — clássico: um patinho de borracha na mesa.

Funciona porque explicar obriga o cérebro a verbalizar as suposições que ele estava pulando na leitura silenciosa. Na maior parte das vezes a pessoa se interrompe no meio da frase: "ah, espera…".

"Não sei, não funciona."
"Aqui eu leio as notas, aqui eu somo cada uma no total — não, espera, eu não estou somando, estou atribuindo…"
Habilidade socioemocional: depurar exige gerenciar o estresse. Manter a calma para diagnosticar com objetividade — em vez de sair mudando linhas no susto — é parte do trabalho técnico.
13 / 25
Pause e responda

Qual erro o computador não avisa?

AEsquecer os dois-pontos no fim do if
BAcessar lista[10] numa lista de 3 itens
CSomar quando deveria multiplicar no cálculo da média ✓
DDividir um número por zero
Por que C: A é sintaxe, B e D são erros de execução — todos interrompem o programa com mensagem. O erro de lógica é o silencioso: sai um número, ele só não é o número certo.
14 / 25
Parte 2 TDD · ponto de partida

E se o teste viesse antes?

Depurar é caro. A pergunta natural é: dá para escrever código de um jeito que gere menos bugs para caçar? Quando o teste vem depois, ele quase sempre é escrito para passar — a gente olha o código pronto e confirma o que ele já faz, inclusive os bugs. Quando vem antes, ele descreve o que o código deveria fazer.

Pense: se você precisasse explicar para outra pessoa o que a função deve fazer, sem mostrar o código, o que escreveria? Essa frase é o seu primeiro teste.

Efeito colateral valioso: escrever o teste primeiro força um design testável — funções curtas, com entrada por parâmetro e saída por return. É exatamente o que vimos na Semana 17.
15 / 25
TDD · Test Driven Development

O ciclo red · green · refactor

1

RED
Escreva um teste para um comportamento que ainda não existe. Rode: ele deve falhar.

2

GREEN
Escreva a implementação mínima que faz o teste passar. Feio pode; errado não.

3

REFACTOR
Melhore o código com a rede de proteção ligada. Os testes seguem verdes.

O passo que todo mundo pula: ver o teste falhar antes de implementar. Se ele passou de primeira, o teste está errado — ele não está testando o que você pensa.
16 / 25
Kata "Calculadora" · iteração 1

Red — o teste que falha

def testar_soma():
    # Arrange
    esperado = 7
    # Act
    obtido = calcular(3, 4, "+")
    # Assert
    assert obtido == esperado, \
        "3 + 4 deveria dar 7"

testar_soma()
Traceback (most recent call last):
  File "kata.py", line 10, in <module>
NameError: name 'calcular' is not defined
Falhou — perfeito. A função calcular nem existe. O teste acabou de definir a assinatura que ela precisa ter: dois números e um operador.
Repare: antes de escrever uma linha de implementação, já decidimos nome, parâmetros e retorno. O teste virou o rascunho do projeto.
17 / 25
Kata "Calculadora" · iteração 1

Green — o mínimo que passa

def calcular(n1, n2, op):
    if op == "+":
        return n1 + n2

testar_soma()
(sem saída — o assert passou em silêncio)
Só a soma? Sim. O TDD manda escrever apenas o suficiente para o teste passar. Nada de já implementar subtração, multiplicação e divisão "de uma vez".
Por que essa disciplina: cada linha de código escrita sem um teste que a exija é uma linha que ninguém garante. É assim que sistemas acumulam funcionalidade que nunca foi verificada.
18 / 25
Kata "Calculadora" · iteração 2

Novo comportamento, novo ciclo

Red — divisão por zero

def testar_divisao_por_zero():
    obtido = calcular(10, 0, "/")
    assert obtido is None, \
        "Divisão por zero deve devolver None"

testar_divisao_por_zero()
AssertionError: Divisão por zero deve devolver None

Green — a implementação mínima

def calcular(n1, n2, op):
    if op == "+":
        return n1 + n2
    if op == "/":
        if n2 == 0:
            return None
        return n1 / n2
(silêncio: os dois testes passam)
O ciclo se repete para subtração, multiplicação e operador inválido. Cada rodada acrescenta um comportamento e um teste — e nenhum dos anteriores pode quebrar.
19 / 25
Kata "Calculadora" · iteração 3

Refactor — agora dá para melhorar

def calcular(n1, n2, op):
    """
    Executa uma operação aritmética simples.

    Args:
        n1 (float): primeiro operando.
        n2 (float): segundo operando.
        op (str): "+", "-", "*" ou "/".

    Returns:
        float: resultado da operação.
        None: se o operador for inválido ou
              se houver divisão por zero.
    """
    if op == "+":
        return n1 + n2
    if op == "-":
        return n1 - n2
    if op == "*":
        return n1 * n2
    if op == "/":
        return None if n2 == 0 else n1 / n2
    return None
OK: testar_soma
OK: testar_subtracao
OK: testar_multiplicacao
OK: testar_divisao
OK: testar_divisao_por_zero
OK: testar_operador_invalido
A docstring entrou no refactor. Ela descreve exatamente os casos que os testes cobrem — documentação e teste contando a mesma história. Fecha o ciclo da semana.
Rede de proteção: reescrever essa função amanhã em duas linhas é seguro. Se algum comportamento se perder, um dos seis testes acusa na hora.
20 / 25
Pause e responda

O teste passou de primeira

Antes de qualquer implementação. O que isso significa?

AQue o código já estava pronto e você pode seguir adiante
BQue o teste provavelmente não está verificando o que você pensa ✓
CQue o TDD não se aplica a esse caso
DQue faltou escrever a docstring antes
Por que B: ver o vermelho é o que prova que o teste funciona. Um teste que nunca falhou é um alarme que nunca foi ligado na tomada.
21 / 25
Visão de mercado

O que o TDD entrega — e o que ele cobra

Entrega

Código nasce testável: funções curtas, com entrada e saída explícitas.

Refatorar deixa de ser risco e vira rotina.

Cobra

Disciplina. O ciclo é curto e repetitivo, e no começo parece mais lento.

O tempo economizado aparece depois, na manutenção — e nas horas de depuração que não aconteceram.
Por que empresas adotam: equipes grandes mudam código que ninguém lembra de ter escrito. A suíte de testes é o que permite modernizar o núcleo do sistema sem medo de causar regressões.
22 / 25
Colocando em prática · 45 minutos · em duplas

O kata é de vocês

Como trabalhar em dupla

1

Navegador escreve o teste (red) e explica o comportamento esperado.

2

Piloto escreve a implementação mínima (green).

3

Refatoram juntos e trocam os papéis a cada ciclo.

Regra do kata: nenhuma linha de implementação sem um teste vermelho antes.

Entrega

  • Ao menos 4 comportamentos testados
  • Cada teste nomeado pelo que ele verifica
  • Docstring na função final
  • Um caso de borda tratado (divisão por zero ou operador inválido)
  • Bônus de depuração: introduzam um bug de propósito, achem com breakpoint e registrem sintoma → causa → correção
23 / 25
Então ficamos assim…

Fechando a Semana 18 ✓

  • Três erros → sintaxe (não roda) · execução (para no meio) · lógica (roda errado calado)
  • Ferramentas → traceback de baixo para cima · print rotulado · breakpoint + step over · Watch/Locals
  • Método → reproduzir → isolar → hipótese → testar → corrigir e escrever o teste
  • TDD → red (ver falhar) · green (mínimo) · refactor (com a rede ligada)
  • Ciclo da semana → documentar o contrato · testar a promessa · depurar a falha
Próximo passo

Com o código documentado, testado e depurável, a Semana 19 volta aos dados: manipulação de strings — e cada função nova já nasce com teste.

24 / 25
Cola de bolso

Depuração e TDD em oito linhas

  • Leia a última linha do traceback antes de qualquer outra coisa
  • Reproduza o erro de propósito antes de tentar corrigir
  • Breakpoint antes do trecho suspeito; uma hipótese por vez
  • Em laço, vigie o acumulador e a condição de parada
  • Bug corrigido sem teste novo é bug que volta
  • TDD: escreva o teste · veja o vermelho · só então implemente
  • Implementação mínima: o suficiente para ficar verde, nada além
  • Refatore somente com todos os testes passando
As duas perguntas do dia: "em que instante essa variável deixou de valer o que deveria?" e "eu conseguiria reescrever essa função amanhã e saber, em um segundo, se quebrei alguma coisa?".
25 / 25
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 3 e 4). Códigos: SISANO1C1B3S18A3 e A4.

BECK, K. Desenvolvimento guiado por testes. Porto Alegre: Bookman, 2010.

ASCENCIO, A. F. G.; CAMPOS, E. A. V. Fundamentos da programação de computadores. São Paulo: Pearson Education do Brasil, 2012.

FORBELLONE, A. L. V.; EBERSPÄCHER, H. F. Lógica de programação: a construção de algoritmos e estruturas de dados. São Paulo: Pearson, 2005.

CÓDIGO FONTE TV. TDD (Test Driven Development) — Dicionário do Programador. YouTube, 10 set. 2018. Disponível em: youtube.com. Acesso em: 23 abr. 2026.

Aula compilada (dobradinha) · adaptação para apresentação HTML por Guilherme Antunes