Pular para o conteúdo
Cursos

DevClub

LógicaFront-endBack-endMobile

IA Club

IA na prática
Estudar programaçãoEstudar IA
ConceitoIniciantecódigo testado

Teste de mesa: executar o algoritmo no papel

A técnica de rodar o algoritmo à mão numa tabela de variáveis, linha a linha, e achar o bug antes de executar, com o Node confirmando o resultado.

Rodolfo Mori9 min de leitura

Teste de mesa é a execução manual de um algoritmo: você escolhe uma entrada, percorre os passos na ordem e anota o estado das variáveis depois de cada mudança. A tabela torna visível a primeira linha em que o resultado real se afasta do esperado.

O caso desta explicação é a média de quatro notas. O resultado mental é 8 para [7, 8, 9, 8]. A implementação defeituosa começa o acumulador em 1, então produz 8,25. Em vez de olhar a última linha e tentar adivinhar, vamos localizar o primeiro estado impossível.

Por que o papel ainda vence o depurador no começo

O depurador mostra com precisão o que o programa fez. O papel exige que você preveja o que ele deveria fazer. Essa diferença ensina a ler atribuição, condição e laço sem depender de botões da ferramenta. Quando previsão e execução discordam, você ganha uma pergunta concreta.

Pense num extrato bancário. O saldo final errado não diz qual lançamento causou o desvio; a sequência de saldos mostra o primeiro lançamento suspeito. Na analogia, cada linha é um estado depois de uma instrução. O limite é que programas também têm chamadas assíncronas, objetos compartilhados e estado externo; uma tabela simples não representa tudo.

O teste de mesa não substitui teste automatizado nem depurador. Ele funciona como lente inicial para uma função pequena ou um caminho específico. Depois que o raciocínio está claro, automatize os casos para impedir regressão.

Prepare quatro coisas antes de preencher

Você precisa do algoritmo numerado, da entrada concreta, do resultado esperado e das colunas de estado. Sem expectativa, qualquer saída parece possível. Sem entrada concreta, as variáveis continuam abstratas.

O pseudocódigo defeituoso é:

text
1. receber notas
2. soma recebe 1
3. contador recebe 0
4. enquanto contador for menor que quantidade de notas
5.   soma recebe soma + nota na posição contador
6.   contador recebe contador + 1
7. média recebe soma / quantidade de notas
8. devolver média

Pseudocódigo vem antes do JavaScript porque o objetivo é enxergar o estado, não discutir sintaxe. Numere operações que mudam variável ou escolhem caminho. A linha do enquanto também entra no rastreio porque seu resultado decide se haverá outra volta.

Uma coluna por variável e uma linha por passo executado

As colunas mínimas são passo, soma, contador e media. Também registramos a condição para não esconder a avaliação do laço. Um traço significa “ainda não existe”, não zero.

passo executado condição contador < 4 soma contador média
entrada
soma = 1 1
contador = 0 1 0
testar laço true 1 0
somar nota 7 8 0
incrementar 8 1
testar laço true 8 1
somar nota 8 16 1
incrementar 16 2
testar laço true 16 2
somar nota 9 25 2
incrementar 25 3
testar laço true 25 3
somar nota 8 33 3
incrementar 33 4
testar laço false 33 4
dividir por 4 33 4 8,25

A tabela tem mais linhas que o pseudocódigo porque as linhas 4 a 6 executam repetidamente. Esse é um ganho, não burocracia: o papel expõe a ordem temporal que o texto compacto do laço esconde.

A primeira divergência aparece antes da primeira volta

Você sabe que nenhuma nota foi somada ainda. Portanto o elemento neutro da soma deveria ser zero. A linha soma = 1 já cria uma diferença de um ponto que atravessará todas as voltas. Não é preciso chegar à divisão para localizar a causa.

Esse diagnóstico é melhor que trocar o divisor até “dar 8”. Alterar o divisor trataria o sintoma para uma lista específica e criaria outro erro em todas as demais. Teste de mesa orienta uma correção mínima: iniciar o acumulador em zero.

O princípio vale para outros estados. Produto começa em um porque um é o elemento neutro da multiplicação. Contador começa em zero quando ainda não houve ocorrências. Maior valor não deve começar sempre em zero se a lista pode conter somente negativos; ele pode começar no primeiro elemento.

O Node confirma o papel, inclusive no erro

A versão defeituosa reproduz exatamente os estados principais:

js
function mediaComErro(notas) {
  let soma = 1;
  let contador = 0;
  while (contador < notas.length) {
    soma += notas[contador];
    contador += 1;
  }
  return soma / notas.length;
}

console.log(mediaComErro([7, 8, 9, 8]));
8.25

O valor não é uma exceção do runtime; é um erro lógico. O Node executou corretamente um algoritmo que descrevemos errado. Essa distinção importa: stack trace ajuda em exceções, mas não aparece quando o programa calcula uma resposta plausível.

Corrija somente o estado inicial:

js
function media(notas) {
  let soma = 0;
  let contador = 0;
  while (contador < notas.length) {
    soma += notas[contador];
    contador += 1;
  }
  return soma / notas.length;
}

console.log(media([7, 8, 9, 8]));
8

Agora a primeira linha de estado é compatível com “nenhuma nota somada”. A lição de acumulador e média aprofunda elementos neutros e lista vazia.

O desenho liga fluxo e tabela

Fluxograma responde “qual passo vem depois?”; tabela de mesa responde “qual valor existe quando ele vem?”. Os dois modelos se complementam:

soma = 0; contador = 0 contador < notas.length? sim somar nota incrementar contador não média = soma / 4 passo soma cont. início 0 0 +7 7 1

As setas dizem que o teste acontece novamente depois do incremento. As colunas mostram que, nessa volta, soma e contador já carregam novos valores. Leia fluxograma e pseudocódigo para treinar a primeira metade desse par.

Dentro de um laço, rastreie as voltas que explicam o defeito

Uma lista de dez mil itens não pede dez mil linhas de papel. Escolha o começo, o ponto de divergência e a borda final. Para erro de um a mais, as duas últimas avaliações são mais informativas que o meio do laço.

js
for (let i = 0; i <= 3; i += 1) {
  console.log({ i, condicao: i <= 3 });
}
console.log({ i: 4, condicao: 4 <= 3, executaCorpo: false });
{ i: 0, condicao: true } { i: 1, condicao: true } { i: 2, condicao: true } { i: 3, condicao: true } { i: 4, condicao: false, executaCorpo: false }

O estado i=4 existe na avaliação, mas não entra no corpo. Essa separação corrige a frase imprecisa “o laço terminou no três”: o último corpo usou três; a condição que encerrou usou quatro. A lição de laço e contador mostra a contagem completa.

Escolha entradas que forçam caminhos diferentes

Um caso normal prova somente o caminho normal. Para média, use pelo menos: quatro notas conhecidas, uma única nota, lista vazia e valores decimais. Para condição, use abaixo, igual e acima do limite. Para busca, use resposta no primeiro item, no último e ausente.

A lista vazia revela outro defeito da função corrigida:

js
function media(notas) {
  const soma = notas.reduce((total, nota) => total + nota, 0);
  return soma / notas.length;
}

console.log(media([]));
console.log(Number.isNaN(media([])));
NaN true

JavaScript não lança erro ao dividir zero por zero; produz NaN. O teste de mesa teria soma=0, quantidade=0 e 0/0, chamando atenção antes da execução. A regra de produto precisa decidir: lista vazia é erro, retorna zero ou não deveria chegar à função?

Onde a técnica deixa de bastar

Concorrência, temporizadores, rede, banco e mutação compartilhada podem produzir ordens difíceis de representar numa tabela manual. Nesses casos, use logs com contexto, depurador, testes automatizados e observabilidade. Mesmo assim, ainda vale recortar uma função pura e rastrear a parte determinística.

O teste de mesa também não garante cobertura sozinho. Você pode preencher a tabela perfeitamente para uma entrada incapaz de visitar o ramo defeituoso. A escolha dos casos é parte da técnica, não uma etapa posterior.

Compare invariantes, não somente números finais

Invariante é uma afirmação que deve continuar verdadeira durante certo trecho. Na média, contador nunca pode ultrapassar a quantidade de notas processadas, e soma precisa representar exatamente os itens anteriores ao índice atual. Registrar a afirmação ao lado da tabela ajuda a detectar um estado impossível antes de conhecer a saída final.

Em busca, uma invariante pode dizer que o alvo não apareceu nas posições já visitadas. Em ordenação por seleção, o prefixo antes da posição atual já está ordenado e contém os menores valores. A técnica muda de simples cópia de variáveis para revisão do motivo pelo qual cada passo é válido.

Use unidades nas colunas. tempoSegundos e distanciaMetros impedem uma divisão tecnicamente executável e conceitualmente errada. Quando um valor muda de unidade, crie nova coluna em vez de sobrescrever e perder a origem da transformação.

Transforme a tabela em casos automatizados

Cada entrada e saída final pode virar teste. Estados intermediários não precisam todos aparecer na suíte pública; eles servem para localizar a causa durante desenvolvimento. Preserve especialmente bordas e regressões: o caso que revelou o acumulador iniciado em um nunca deve desaparecer.

Nomeie o teste pelo comportamento, como “média de lista vazia rejeita entrada”, e não pela função interna. Assim a implementação pode mudar sem apagar o contrato. Quando o teste falha, refaça uma tabela curta com a entrada daquele cenário, compare a primeira divergência e corrija somente a causa.

O papel continua útil mesmo depois de adotar ferramenta. Você pode desenhar uma hipótese em dois minutos antes de encher o código de logs. A disciplina é formular o estado esperado; a mídia — papel, planilha ou depurador — é secundária.

Uma revisão em dupla melhora a hipótese

Peça para a outra pessoa escolher a entrada e preencher uma coluna, enquanto você executa os passos. Divergências de interpretação revelam pseudocódigo ambíguo. Depois troquem os papéis e usem um caso de borda.

Não diga o bug antes da simulação. Se a pessoa encontra a linha do acumulador sem pista, a tabela está cumprindo o papel de diagnóstico. Se ela só percebe depois de receber a resposta, acrescente expectativa e invariante mais cedo no processo.

Arquive apenas tabelas que explicam uma regra ou um defeito importante. O objetivo não é produzir papel para toda execução, mas preservar o raciocínio que será útil quando o requisito voltar a mudar. Uma tabela pequena com entrada, primeira divergência e correção ensina mais que dezenas de estados sem hipótese.

Sua missão é rastrear no papel um desconto por faixas para valores 99, 100 e 101. Numere passos, anote condição e resultado, e marque a primeira linha que muda entre os casos. Depois transforme cada linha final em um teste executável. Use a estrutura condicional para a regra, o guia de lógica para situar a técnica e a trilha de Lógica para continuar.

  • teste de mesa
  • rastreio
  • depuracao
  • algoritmo
  • tabela de variaveis

Perguntas frequentes

Teste de mesa é a mesma coisa que depurar com breakpoint?
Não. Os dois observam estado, mas o teste de mesa é uma simulação manual feita a partir do algoritmo. Breakpoint pausa uma execução real e mostra o estado produzido pelo runtime.
Preciso rastrear todas as linhas de um programa grande?
Não. Recorte a função e o caso que podem explicar o defeito. Dentro de um laço longo, registre as primeiras voltas, a volta em que o estado diverge e a borda final.
Qual entrada usar primeiro no teste de mesa?
Comece com um caso pequeno cujo resultado você calcula mentalmente. Depois use vazio, limite e extremo para expor caminhos que o caso normal não visita.

Dúvidas e comentários

Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.

Todo o código deste artigo foi executado em Node v26.3.0, e as saídas exibidas são as reais — como produzimos este conteúdo.

Fontes consultadas

  1. Node.js — Debugging Getting Started — nodejs.org
  2. ECMAScript — Execution Contexts — tc39.es

Continue por aqui