Testes e qualidade de código

Código legado: teste o comportamento antes de refatorar

Nove casos de borda de uma função de desconto separam refatoração de mudança de regra e mostram por que preservar um resultado não garante sua correção.

2 min de leitura
Imagem de capa de Código legado: teste o comportamento antes de refatorar

Para alterar código legado com segurança, registre os resultados atuais e separe mudanças de estrutura de mudanças de regra. Um teste de caracterização descreve o comportamento existente; não garante que a regra de negócio esteja correta.

Mecanismo e decisão de projeto

Refatorar altera a estrutura interna preservando o comportamento observável. Se a regra não está clara, registre limites das condições, valores ausentes e caminhos de falha, além das entradas normais. Aqui a função original desconta 30 de um valor positivo para clientes do tipo B. Fonte primária

Código reproduzível

Este exemplo construído troca o condicional original por uma expressão de desconto. Nove casos incluem -1, 0, 1, 29, 30, 31, 100 e outro tipo de cliente. Os resultados esperados estão em uma tabela independente, em vez de serem obtidos chamando a função antiga.

Este exemplo independente foi executado em 2026-10-23 com Apple Swift 6.4 para arm64 macOS, no modo de linguagem Swift 6. Não requer rede nem pacotes adicionais.

Baixar o arquivo Swift completo

Execute o comando na pasta do download. As precondições interrompem a execução se uma verificação falhar. Não use -Ounchecked: essa opção remove as verificações.

swift -swift-version 6 legacy-code-maintenance-problems.swift
func legacyPrice(kind: String, amount: Int) -> Int {
    if kind == "B" && amount > 0 { return amount - 30 }
    return amount
}

func refactoredPrice(kind: String, amount: Int) -> Int {
    let discount = kind == "B" && amount > 0 ? 30 : 0
    return amount - discount
}

let cases: [(String, Int, Int)] = [
    ("B", -1, -1), ("B", 0, 0), ("B", 1, -29),
    ("B", 29, -1), ("B", 30, 0), ("B", 31, 1),
    ("B", 100, 70), ("A", 100, 100), ("A", 0, 0)
]
var clampDifferences = 0
for (kind, amount, expected) in cases {
    precondition(legacyPrice(kind: kind, amount: amount) == expected)
    precondition(refactoredPrice(kind: kind, amount: amount) == expected)
    let changed = kind == "B" && amount > 0 ? max(0, amount - 30) : amount
    if changed != expected { clampDifferences += 1 }
}
precondition(clampDifferences == 2)
print("cases=9 preserved=9 clamp-differences=2")

Saída registrada e interpretação

cases=9 preserved=9 clamp-differences=2

As duas implementações coincidem nos nove resultados. Limitar totais negativos a zero altera os casos de valor 1 e 29. A verificação separada clamp-differences=2 demonstra essa mudança de regra; não esconde um teste de preservação que falhou.

Escopo e limitações

Isso não recomenda permitir cobranças negativas. Confirme a política real com o responsável. O experimento usa inteiros pequenos e não cobre impostos, arredondamento monetário, overflow ou efeitos de banco de dados. Nove casos também não provam equivalência para todas as entradas.

O que verificar em seguida

Examine os pontos de chamada e os dados armazenados para ampliar os casos. Se totais negativos devem ser proibidos, combine novas expectativas e aplique uma mudança separada. Se o banco impedir testes isolados, continue com o exemplo de injeção do armazenamento.

Experimento relacionado

Fontes e verificação

  • Definition of RefactoringMartin Fowler · Fonte original do autor · Consultado 23 de outubro de 2026Evidência: Fonte do contrato de implementação e da explicação. A saída foi verificada separadamente com o experimento incluído aqui.