16  Testes e refatoração

Mudar a estrutura sem perder comportamento

16.1 Objetivos de aprendizagem

Ao concluir este capítulo, você deverá ser capaz de:

  • transformar requisitos em casos de teste;
  • separar teste de unidade e teste de fluxo;
  • aplicar o ciclo vermelho–verde–refatorar;
  • reconhecer duplicação e responsabilidades excessivas;
  • refatorar preservando resultados observáveis.

16.2 Teste como especificação

Ciclo que passa por teste falhando, implementação mínima, teste passando e refatoração, retornando ao início.

Ciclo curto de desenvolvimento orientado por testes.

Um teste contém preparação, ação e verificação. Antes de adotar uma biblioteca externa, é possível praticar a ideia com um verificador simples:

import java.util.Locale;

public class Capitulo15Testes {
    static String normalizar(String entrada) {
        if (entrada == null) {
            return "";
        }
        return entrada.strip().toLowerCase(Locale.ROOT);
    }

    static void verificar(String descricao, Object esperado, Object obtido) {
        if (!esperado.equals(obtido)) {
            throw new AssertionError(
                    descricao + " | esperado=" + esperado + ", obtido=" + obtido);
        }
    }

    public static void main(String[] args) {
        verificar("remove espaços", "ajuda", normalizar("  ajuda "));
        verificar("ignora maiúsculas", "dica", normalizar("DICA"));
        verificar("trata null", "", normalizar(null));

        System.out.println("3 testes passaram.");
    }
}

Esse recurso didático não substitui JUnit em projetos profissionais, mas torna explícita a estrutura de um teste sem adicionar dependências ao livro.

16.3 Casos de borda

Para cada método, cubra:

  • caso comum;
  • entrada vazia;
  • limites mínimo e máximo;
  • valor desconhecido;
  • erro esperado;
  • estado antes e depois da operação.

Um teste deve falhar por um motivo claro. Evite reunir muitas regras em uma única verificação.

16.4 Refatoração

Uma estudante reclama que o teste quebrou o programa e o JavaBot explica que o teste apenas revelou o problema.

Quadrinho: o teste que encontrou um bug.

Refatorar é alterar a estrutura interna sem modificar o comportamento externo. Um ciclo seguro é:

  1. escrever ou executar testes;
  2. fazer uma mudança pequena;
  3. executar os testes novamente;
  4. registrar a decisão importante.

Sinais de refatoração:

  • método longo;
  • cadeia extensa de if ou switch;
  • regra repetida;
  • classe com responsabilidades não relacionadas;
  • coleção interna exposta;
  • dependência direta de console em regras de negócio.

16.5 Roteiro de regressão do chatbot

Além dos testes de métodos, execute um fluxo completo:

Cenário Entrada Resultado esperado
ajuda ajuda todos os comandos aparecem
normalização DICA comando encontrado
vazio linha em branco orientação, sem histórico
histórico oi, historico interação anterior exibida
persistência encerrar sessão arquivo contém as linhas registradas
duplicação registrar dois comandos iguais exceção clara

16.6 Evolução do projeto: versão 15

Crie testes para normalização, registro de comandos e histórico antes de trocar condicionais por objetos polimórficos. Se os mesmos testes continuarem passando, a refatoração preservou o contrato.

O exemplo completo está em examples/src/Capitulo15Testes.java.

16.7 Prática verificável

  1. Faça um teste falhar de propósito e leia a mensagem.
  2. Teste uma exceção esperada com try/catch.
  3. Extraia uma regra duplicada e confirme que os testes permanecem verdes.
  4. Escreva um roteiro manual com entrada e saída exatas para o projeto final.
DicaPróximo passo profissional

Depois de dominar a estrutura, migre esses casos para JUnit em um projeto Maven ou Gradle. A biblioteca muda; a lógica de preparação, ação e verificação permanece.