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
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
Refatorar é alterar a estrutura interna sem modificar o comportamento externo. Um ciclo seguro é:
- escrever ou executar testes;
- fazer uma mudança pequena;
- executar os testes novamente;
- registrar a decisão importante.
Sinais de refatoração:
- método longo;
- cadeia extensa de
ifouswitch; - 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
- Faça um teste falhar de propósito e leia a mensagem.
- Teste uma exceção esperada com
try/catch. - Extraia uma regra duplicada e confirme que os testes permanecem verdes.
- Escreva um roteiro manual com entrada e saída exatas para o projeto final.
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.